diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index fd222bcf0f5..d030c36678c 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -199,10 +199,11 @@
android:title="@string/enable_terminal_title"
android:summary="@string/enable_terminal_summary" />
-
+ android:summary="@string/enable_linux_terminal_summary"
+ android:fragment="com.android.settings.development.linuxterminal.LinuxTerminalDashboardFragment" />
+
+
+
+
+
+
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java
index 1e5145acb6d..de6e158db2c 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java
@@ -20,6 +20,7 @@ import android.util.ArrayMap;
import com.android.settings.accounts.AccountDashboardFragment;
import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.development.linuxterminal.LinuxTerminalDashboardFragment;
import com.android.settings.deviceinfo.StorageDashboardFragment;
import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment;
@@ -52,5 +53,8 @@ public class ProfileFragmentBridge {
ProfileSelectKeyboardFragment.class.getName());
FRAGMENT_MAP.put(NewKeyboardLayoutEnabledLocalesFragment.class.getName(),
ProfileSelectPhysicalKeyboardFragment.class.getName());
+ FRAGMENT_MAP.put(
+ LinuxTerminalDashboardFragment.class.getName(),
+ ProfileSelectLinuxTerminalFragment.class.getName());
}
}
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java
index 494ef95f99b..270ab9c231e 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java
@@ -331,23 +331,29 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
for (UserInfo userInfo : userInfos) {
if (userInfo.isMain()) {
- fragments.add(createAndGetFragment(
- ProfileType.PERSONAL,
- bundle != null ? bundle : new Bundle(),
- personalFragmentConstructor));
+ fragments.add(
+ createAndGetFragment(
+ ProfileType.PERSONAL,
+ userInfo.id,
+ bundle != null ? bundle : new Bundle(),
+ personalFragmentConstructor));
} else if (userInfo.isManagedProfile()) {
- fragments.add(createAndGetFragment(
- ProfileType.WORK,
- bundle != null ? bundle.deepCopy() : new Bundle(),
- workFragmentConstructor));
+ fragments.add(
+ createAndGetFragment(
+ ProfileType.WORK,
+ userInfo.id,
+ bundle != null ? bundle.deepCopy() : new Bundle(),
+ workFragmentConstructor));
} else if (Flags.allowPrivateProfile()
&& android.multiuser.Flags.enablePrivateSpaceFeatures()
&& userInfo.isPrivateProfile()) {
if (!privateSpaceInfoProvider.isPrivateSpaceLocked(context)) {
- fragments.add(createAndGetFragment(
- ProfileType.PRIVATE,
- bundle != null ? bundle.deepCopy() : new Bundle(),
- privateFragmentConstructor));
+ fragments.add(
+ createAndGetFragment(
+ ProfileType.PRIVATE,
+ userInfo.id,
+ bundle != null ? bundle.deepCopy() : new Bundle(),
+ privateFragmentConstructor));
}
} else {
Log.d(TAG, "Not showing tab for unsupported user " + userInfo);
@@ -364,8 +370,12 @@ public abstract class ProfileSelectFragment extends DashboardFragment {
}
private static Fragment createAndGetFragment(
- @ProfileType int profileType, Bundle bundle, FragmentConstructor fragmentConstructor) {
+ @ProfileType int profileType,
+ int userId,
+ Bundle bundle,
+ FragmentConstructor fragmentConstructor) {
bundle.putInt(EXTRA_PROFILE, profileType);
+ bundle.putInt(EXTRA_USER_ID, userId);
final Fragment fragment = fragmentConstructor.constructAndGetFragment();
fragment.setArguments(bundle);
return fragment;
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectLinuxTerminalFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectLinuxTerminalFragment.java
new file mode 100644
index 00000000000..c10a3e2e387
--- /dev/null
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectLinuxTerminalFragment.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard.profileselector;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.development.DeveloperOptionAwareMixin;
+import com.android.settings.development.linuxterminal.LinuxTerminalDashboardFragment;
+
+/** Linux terminal preferences at developers option for personal/managed profile. */
+public class ProfileSelectLinuxTerminalFragment extends ProfileSelectFragment
+ implements DeveloperOptionAwareMixin {
+
+ private static final String TAG = "ProfileSelLinuxTerminalFrag";
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ @NonNull
+ public Fragment[] getFragments() {
+ return getFragments(
+ getContext(),
+ getArguments(),
+ LinuxTerminalDashboardFragment::new,
+ LinuxTerminalDashboardFragment::new,
+ LinuxTerminalDashboardFragment::new);
+ }
+}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 8f2a13cfcf8..922c897cab8 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -72,6 +72,7 @@ import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferen
import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController;
import com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController;
import com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController;
+import com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController;
import com.android.settings.development.qstile.DevelopmentTiles;
import com.android.settings.development.storage.SharedDataPreferenceController;
import com.android.settings.overlay.FeatureFactory;
diff --git a/src/com/android/settings/development/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/LinuxTerminalPreferenceController.java
deleted file mode 100644
index 3e419e408fc..00000000000
--- a/src/com/android/settings/development/LinuxTerminalPreferenceController.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.TwoStatePreference;
-
-import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.development.DeveloperOptionsPreferenceController;
-
-public class LinuxTerminalPreferenceController extends DeveloperOptionsPreferenceController
- implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
- private static final String TAG = "LinuxTerminalPrefCtrl";
-
- private static final String ENABLE_TERMINAL_KEY = "enable_linux_terminal";
-
- @NonNull
- private final PackageManager mPackageManager;
-
- @Nullable
- private final String mTerminalPackageName;
-
- public LinuxTerminalPreferenceController(@NonNull Context context) {
- super(context);
- mPackageManager = mContext.getPackageManager();
-
- String packageName = mContext.getString(R.string.config_linux_terminal_app_package_name);
- mTerminalPackageName =
- isPackageInstalled(mPackageManager, packageName) ? packageName : null;
-
- Log.d(TAG, "Terminal app package name=" + packageName + ", isAvailable=" + isAvailable());
- }
-
- // Avoid lazy initialization because this may be called before displayPreference().
- @Override
- public boolean isAvailable() {
- // Returns true only if the terminal app is installed which only happens when the build flag
- // RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES is true.
- // TODO(b/343795511): Add explicitly check for the flag when it's accessible from Java code.
- return getTerminalPackageName() != null;
- }
-
- @Override
- @NonNull
- public String getPreferenceKey() {
- return ENABLE_TERMINAL_KEY;
- }
-
- @Override
- public void displayPreference(@NonNull PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference.setEnabled(isAvailable());
- }
-
- @Override
- public boolean onPreferenceChange(
- @NonNull Preference preference, @NonNull Object newValue) {
- String packageName = getTerminalPackageName();
- if (packageName == null) {
- return false;
- }
-
- boolean terminalEnabled = (Boolean) newValue;
- int state = terminalEnabled
- ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
- mPackageManager.setApplicationEnabledSetting(packageName, state, /* flags=*/ 0);
- ((TwoStatePreference) mPreference).setChecked(terminalEnabled);
- return true;
- }
-
- @Override
- public void updateState(@NonNull Preference preference) {
- String packageName = getTerminalPackageName();
- if (packageName == null) {
- return;
- }
-
- boolean isTerminalEnabled = mPackageManager.getApplicationEnabledSetting(packageName)
- == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
- ((TwoStatePreference) mPreference).setChecked(isTerminalEnabled);
- }
-
- // Can be mocked for testing
- @VisibleForTesting
- @Nullable
- String getTerminalPackageName() {
- return mTerminalPackageName;
- }
-
- private static boolean isPackageInstalled(PackageManager manager, String packageName) {
- if (TextUtils.isEmpty(packageName)) {
- return false;
- }
- try {
- return manager.getPackageInfo(
- packageName,
- PackageManager.MATCH_ALL | PackageManager.MATCH_DISABLED_COMPONENTS) != null;
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-}
diff --git a/src/com/android/settings/development/linuxterminal/EnableLinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/EnableLinuxTerminalPreferenceController.java
new file mode 100644
index 00000000000..5989aebb078
--- /dev/null
+++ b/src/com/android/settings/development/linuxterminal/EnableLinuxTerminalPreferenceController.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.linuxterminal;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.CompoundButton;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.SettingsMainSwitchPreference;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/** Preference controller for enable/disable toggle of the linux terminal */
+public class EnableLinuxTerminalPreferenceController extends BasePreferenceController
+ implements CompoundButton.OnCheckedChangeListener, PreferenceControllerMixin {
+ @VisibleForTesting
+ static final int TERMINAL_PACKAGE_NAME_RESID = R.string.config_linux_terminal_app_package_name;
+
+ private static final String TAG = "LinuxTerminalPrefCtrl";
+
+ private static final String ENABLE_TERMINAL_KEY = "enable_linux_terminal";
+
+ @NonNull private final PackageManager mPackageManager;
+ private final boolean mIsPrimaryUser;
+ @Nullable private final String mTerminalPackageName;
+
+ @Nullable private SettingsMainSwitchPreference mPreference;
+
+ public EnableLinuxTerminalPreferenceController(
+ @NonNull Context context, @NonNull Context userAwareContext, int userId) {
+ this(context, userAwareContext, userId == UserHandle.myUserId());
+ }
+
+ @VisibleForTesting
+ EnableLinuxTerminalPreferenceController(
+ @NonNull Context context, @NonNull Context userAwareContext, boolean isPrimaryUser) {
+ super(context, ENABLE_TERMINAL_KEY);
+
+ mPackageManager = userAwareContext.getPackageManager();
+ mIsPrimaryUser = isPrimaryUser;
+
+ String packageName =
+ userAwareContext.getString(R.string.config_linux_terminal_app_package_name);
+ mTerminalPackageName =
+ isPackageInstalled(mPackageManager, packageName) ? packageName : null;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(@NonNull PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ if (mPreference != null) {
+ mPreference.addOnSwitchChangeListener(this);
+ }
+ }
+
+ @Override
+ public void onCheckedChanged(@NonNull CompoundButton buttonView, boolean isChecked) {
+ if (mTerminalPackageName == null) {
+ return;
+ }
+
+ int state =
+ isChecked
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ mPackageManager.setApplicationEnabledSetting(mTerminalPackageName, state, /* flags= */ 0);
+ }
+
+ @Override
+ @SuppressWarnings("NullAway") // setDisabledByAdmin(EnforcedAdmin) doesn't have @Nullable
+ public void updateState(@NonNull Preference preference) {
+ if (mPreference != preference) {
+ return;
+ }
+
+ boolean isInstalled = (mTerminalPackageName != null);
+ if (isInstalled) {
+ mPreference.setDisabledByAdmin(/* admin= */ null);
+ mPreference.setEnabled(/* enabled= */ true);
+ boolean terminalEnabled =
+ mPackageManager.getApplicationEnabledSetting(mTerminalPackageName)
+ == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ mPreference.setChecked(terminalEnabled);
+ } else {
+ if (mIsPrimaryUser) {
+ Log.e(TAG, "Terminal app doesn't exist for primary user but UI was shown");
+ mPreference.setDisabledByAdmin(/* admin= */ null);
+ mPreference.setEnabled(/* enabled= */ false);
+ } else {
+ // If admin hasn't enabled the system app, mark it as disabled by admin.
+ mPreference.setDisabledByAdmin(new EnforcedAdmin());
+ // Make it enabled, so clicking it would show error dialog.
+ mPreference.setEnabled(/* enabled= */ true);
+ }
+ mPreference.setChecked(/* checked= */ false);
+ }
+ }
+
+ private static boolean isPackageInstalled(PackageManager manager, String packageName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return false;
+ }
+ try {
+ return manager.getPackageInfo(
+ packageName,
+ PackageManager.MATCH_ALL | PackageManager.MATCH_DISABLED_COMPONENTS)
+ != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalDashboardFragment.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalDashboardFragment.java
new file mode 100644
index 00000000000..0eeeeddf790
--- /dev/null
+++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalDashboardFragment.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.linuxterminal;
+
+import static android.content.Intent.EXTRA_USER_ID;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Fragment shown for 'Linux terminal development' preference in developer option. */
+@SearchIndexable
+public class LinuxTerminalDashboardFragment extends DashboardFragment {
+ private static final String TAG = "LinuxTerminalFrag";
+
+ private Context mUserAwareContext;
+
+ private int mUserId;
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.LINUX_TERMINAL_DASHBOARD;
+ }
+
+ @NonNull
+ @Override
+ public String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getPreferenceScreenResId() {
+ return R.xml.linux_terminal_settings;
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ // Initialize mUserId and mUserAwareContext before super.onAttach(),
+ // so createPreferenceControllers() can be called with proper values from super.onAttach().
+ int currentUserId = UserHandle.myUserId();
+ mUserId = getArguments().getInt(EXTRA_USER_ID, currentUserId);
+ mUserAwareContext =
+ (currentUserId == mUserId)
+ ? context
+ : context.createContextAsUser(UserHandle.of(mUserId), /* flags= */ 0);
+
+ // Note: This calls createPreferenceControllers() inside.
+ super.onAttach(context);
+ }
+
+ @Override
+ @NonNull
+ public List createPreferenceControllers(
+ @NonNull Context context) {
+ List list = new ArrayList<>();
+ list.add(new EnableLinuxTerminalPreferenceController(context, mUserAwareContext, mUserId));
+ return list;
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.linux_terminal_settings) {
+
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
+ }
+ };
+}
diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
new file mode 100644
index 00000000000..b3a0f801f61
--- /dev/null
+++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.linuxterminal;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/** Preference controller for Linux terminal option in developers option */
+public class LinuxTerminalPreferenceController extends DeveloperOptionsPreferenceController
+ implements PreferenceControllerMixin {
+ @VisibleForTesting
+ static final int TERMINAL_PACKAGE_NAME_RESID = R.string.config_linux_terminal_app_package_name;
+
+ private static final String LINUX_TERMINAL_KEY = "linux_terminal";
+
+ @Nullable private final String mTerminalPackageName;
+
+ public LinuxTerminalPreferenceController(@NonNull Context context) {
+ super(context);
+ String packageName = context.getString(TERMINAL_PACKAGE_NAME_RESID);
+ mTerminalPackageName =
+ isPackageInstalled(context.getPackageManager(), packageName) ? packageName : null;
+ }
+
+ // Avoid lazy initialization because this may be called before displayPreference().
+ @Override
+ public boolean isAvailable() {
+ // Returns true only if the terminal app is installed which only happens when the build flag
+ // RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES is true.
+ // TODO(b/343795511): Add explicitly check for the flag when it's accessible from Java code.
+ return mTerminalPackageName != null;
+ }
+
+ @Override
+ @NonNull
+ public String getPreferenceKey() {
+ return LINUX_TERMINAL_KEY;
+ }
+
+ private static boolean isPackageInstalled(PackageManager manager, String packageName) {
+ if (TextUtils.isEmpty(packageName)) {
+ return false;
+ }
+ try {
+ return manager.getPackageInfo(
+ packageName,
+ PackageManager.MATCH_ALL | PackageManager.MATCH_DISABLED_COMPONENTS)
+ != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/LinuxTerminalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/LinuxTerminalPreferenceControllerTest.java
deleted file mode 100644
index 96b6d6aa3d5..00000000000
--- a/tests/robotests/src/com/android/settings/development/LinuxTerminalPreferenceControllerTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class LinuxTerminalPreferenceControllerTest {
-
- @Mock
- private Context mContext;
- @Mock
- private SwitchPreference mPreference;
- @Mock
- private PreferenceScreen mPreferenceScreen;
- @Mock
- private PackageManager mPackageManager;
- @Mock
- private ApplicationInfo mApplicationInfo;
-
- private String mTerminalPackageName = "com.android.virtualization.terminal";
- private LinuxTerminalPreferenceController mController;
-
- @Before
- public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
- doReturn(mPackageManager).when(mContext).getPackageManager();
- doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(
- eq(mTerminalPackageName), any());
-
- mController = spy(new LinuxTerminalPreferenceController(mContext));
- doReturn(true).when(mController).isAvailable();
- doReturn(mTerminalPackageName).when(mController).getTerminalPackageName();
- when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
- .thenReturn(mPreference);
- mController.displayPreference(mPreferenceScreen);
- }
-
- @Test
- public void isAvailable_whenPackageNameIsNull_returnsFalse() throws Exception {
- mController = spy(new LinuxTerminalPreferenceController(mContext));
- doReturn(null).when(mController).getTerminalPackageName();
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_whenAppDoesNotExist_returnsFalse() throws Exception {
- doThrow(new NameNotFoundException()).when(mPackageManager).getApplicationInfo(
- eq(mTerminalPackageName), any());
-
- mController = spy(new LinuxTerminalPreferenceController(mContext));
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void onPreferenceChanged_turnOnTerminal() {
- mController.onPreferenceChange(null, true);
-
- verify(mPackageManager).setApplicationEnabledSetting(
- mTerminalPackageName,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- /* flags= */ 0);
- }
-
- @Test
- public void onPreferenceChanged_turnOffTerminal() {
- mController.onPreferenceChange(null, false);
-
- verify(mPackageManager).setApplicationEnabledSetting(
- mTerminalPackageName,
- PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
- /* flags= */ 0);
- }
-
- @Test
- public void updateState_preferenceShouldBeChecked() {
- when(mPackageManager.getApplicationEnabledSetting(mTerminalPackageName))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
- mController.updateState(mPreference);
-
- verify(mPreference).setChecked(true);
- }
-
- @Test
- public void updateState_preferenceShouldNotBeChecked() {
- when(mPackageManager.getApplicationEnabledSetting(mTerminalPackageName))
- .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
- mController.updateState(mPreference);
-
- verify(mPreference).setChecked(false);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/development/linuxterminal/EnableLinuxTerminalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/linuxterminal/EnableLinuxTerminalPreferenceControllerTest.java
new file mode 100644
index 00000000000..80d5ca5034d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/linuxterminal/EnableLinuxTerminalPreferenceControllerTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.linuxterminal;
+
+import static com.android.settings.development.linuxterminal.EnableLinuxTerminalPreferenceController.TERMINAL_PACKAGE_NAME_RESID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.widget.SettingsMainSwitchPreference;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.ParameterizedRobolectricTestRunner;
+
+import java.util.Arrays;
+import java.util.List;
+
+/** Tests {@link EnableLinuxTerminalPreferenceController} */
+@RunWith(ParameterizedRobolectricTestRunner.class)
+public class EnableLinuxTerminalPreferenceControllerTest {
+
+ /** Defines parameters for parameterized test */
+ @ParameterizedRobolectricTestRunner.Parameters(
+ name = "isPrimaryUser={0}, installed={1}, enabled={2}")
+ public static List