• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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.settings.development.linuxterminal;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.os.UserHandle;
22 import android.text.TextUtils;
23 import android.util.Log;
24 import android.widget.CompoundButton;
25 
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.VisibleForTesting;
29 import androidx.preference.Preference;
30 import androidx.preference.PreferenceScreen;
31 
32 import com.android.settings.R;
33 import com.android.settings.core.BasePreferenceController;
34 import com.android.settings.core.PreferenceControllerMixin;
35 import com.android.settings.widget.SettingsMainSwitchPreference;
36 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
37 
38 /** Preference controller for enable/disable toggle of the linux terminal */
39 public class EnableLinuxTerminalPreferenceController extends BasePreferenceController
40         implements CompoundButton.OnCheckedChangeListener, PreferenceControllerMixin {
41     @VisibleForTesting
42     static final int TERMINAL_PACKAGE_NAME_RESID = R.string.config_linux_terminal_app_package_name;
43 
44     private static final String TAG = "LinuxTerminalPrefCtrl";
45 
46     private static final String ENABLE_TERMINAL_KEY = "enable_linux_terminal";
47 
48     @NonNull private final PackageManager mPackageManager;
49     private final boolean mIsPrimaryUser;
50     @Nullable private final String mTerminalPackageName;
51 
52     @Nullable private SettingsMainSwitchPreference mPreference;
53 
EnableLinuxTerminalPreferenceController( @onNull Context context, @NonNull Context userAwareContext, int userId)54     public EnableLinuxTerminalPreferenceController(
55             @NonNull Context context, @NonNull Context userAwareContext, int userId) {
56         this(context, userAwareContext, userId == UserHandle.myUserId());
57     }
58 
59     @VisibleForTesting
EnableLinuxTerminalPreferenceController( @onNull Context context, @NonNull Context userAwareContext, boolean isPrimaryUser)60     EnableLinuxTerminalPreferenceController(
61             @NonNull Context context, @NonNull Context userAwareContext, boolean isPrimaryUser) {
62         super(context, ENABLE_TERMINAL_KEY);
63 
64         mPackageManager = userAwareContext.getPackageManager();
65         mIsPrimaryUser = isPrimaryUser;
66 
67         String packageName =
68                 userAwareContext.getString(R.string.config_linux_terminal_app_package_name);
69         mTerminalPackageName =
70                 isPackageInstalled(mPackageManager, packageName) ? packageName : null;
71     }
72 
73     @Override
getAvailabilityStatus()74     public int getAvailabilityStatus() {
75         return AVAILABLE;
76     }
77 
78     @Override
displayPreference(@onNull PreferenceScreen screen)79     public void displayPreference(@NonNull PreferenceScreen screen) {
80         super.displayPreference(screen);
81         mPreference = screen.findPreference(getPreferenceKey());
82         if (mPreference != null) {
83             mPreference.addOnSwitchChangeListener(this);
84         }
85     }
86 
87     @Override
onCheckedChanged(@onNull CompoundButton buttonView, boolean isChecked)88     public void onCheckedChanged(@NonNull CompoundButton buttonView, boolean isChecked) {
89         if (mTerminalPackageName == null) {
90             return;
91         }
92 
93         int state =
94                 isChecked
95                         ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
96                         : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
97         mPackageManager.setApplicationEnabledSetting(mTerminalPackageName, state, /* flags= */ 0);
98         if (!isChecked) {
99             mPackageManager.clearApplicationUserData(
100                     mTerminalPackageName, /* observer= */ null);
101         }
102     }
103 
104     @Override
105     @SuppressWarnings("NullAway") // setDisabledByAdmin(EnforcedAdmin) doesn't have @Nullable
updateState(@onNull Preference preference)106     public void updateState(@NonNull Preference preference) {
107         if (mPreference != preference) {
108             return;
109         }
110 
111         boolean isInstalled = (mTerminalPackageName != null);
112         if (isInstalled) {
113             mPreference.setDisabledByAdmin(/* admin= */ null);
114             mPreference.setEnabled(/* enabled= */ true);
115             boolean terminalEnabled =
116                     mPackageManager.getApplicationEnabledSetting(mTerminalPackageName)
117                             == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
118             mPreference.setChecked(terminalEnabled);
119         } else {
120             if (mIsPrimaryUser) {
121                 Log.e(TAG, "Terminal app doesn't exist for primary user but UI was shown");
122                 mPreference.setDisabledByAdmin(/* admin= */ null);
123                 mPreference.setEnabled(/* enabled= */ false);
124             } else {
125                 // If admin hasn't enabled the system app, mark it as disabled by admin.
126                 mPreference.setDisabledByAdmin(new EnforcedAdmin());
127                 // Make it enabled, so clicking it would show error dialog.
128                 mPreference.setEnabled(/* enabled= */ true);
129             }
130             mPreference.setChecked(/* checked= */ false);
131         }
132     }
133 
isPackageInstalled(PackageManager manager, String packageName)134     private static boolean isPackageInstalled(PackageManager manager, String packageName) {
135         if (TextUtils.isEmpty(packageName)) {
136             return false;
137         }
138         try {
139             return manager.getPackageInfo(
140                             packageName,
141                             PackageManager.MATCH_ALL | PackageManager.MATCH_DISABLED_COMPONENTS)
142                     != null;
143         } catch (PackageManager.NameNotFoundException e) {
144             return false;
145         }
146     }
147 }
148