From a6334bc0a3a66ee6194991eb1c941ab7dbea365a Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Fri, 15 Nov 2024 00:40:21 +0900 Subject: [PATCH] Hide Linux terminal if device doesn't meet minimum requirement Bug: 366374130 Test: Manually, atest Change-Id: Id0ef47099b3fab41175bfae3d0eaf61037ba82ff --- .../LinuxTerminalPreferenceController.java | 30 +++++++++++-- ...LinuxTerminalPreferenceControllerTest.java | 44 +++++++++++++++++-- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java index b3a0f801f61..f21f2b5700b 100644 --- a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java +++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java @@ -18,7 +18,10 @@ package com.android.settings.development.linuxterminal; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Process; +import android.os.storage.StorageManager; import android.text.TextUtils; +import android.util.DataUnit; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,30 +31,45 @@ import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; +import java.util.Objects; + /** 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; + @VisibleForTesting + static final long MEMORY_MIN_BYTES = DataUnit.GIGABYTES.toBytes(4); // 4_000_000_000 + + @VisibleForTesting + static final long STORAGE_MIN_BYTES = DataUnit.GIBIBYTES.toBytes(128); // 128 * 2^30 + private static final String LINUX_TERMINAL_KEY = "linux_terminal"; @Nullable private final String mTerminalPackageName; + private final boolean mIsDeviceCapable; public LinuxTerminalPreferenceController(@NonNull Context context) { super(context); String packageName = context.getString(TERMINAL_PACKAGE_NAME_RESID); mTerminalPackageName = isPackageInstalled(context.getPackageManager(), packageName) ? packageName : null; + + StorageManager storageManager = + Objects.requireNonNull(context.getSystemService(StorageManager.class)); + mIsDeviceCapable = + getTotalMemory() >= MEMORY_MIN_BYTES + && storageManager.getPrimaryStorageSize() >= STORAGE_MIN_BYTES; } // 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. + // Check build flag RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES indirectly + // by checking whether the terminal app is installed. // TODO(b/343795511): Add explicitly check for the flag when it's accessible from Java code. - return mTerminalPackageName != null; + return mTerminalPackageName != null && mIsDeviceCapable; } @Override @@ -73,4 +91,10 @@ public class LinuxTerminalPreferenceController extends DeveloperOptionsPreferenc return false; } } + + // Can be overridden for test + @VisibleForTesting + long getTotalMemory() { + return Process.getTotalMemory(); + } } diff --git a/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java index 17c34356297..fffe6b10a1c 100644 --- a/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.development.linuxterminal; +import static com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController.MEMORY_MIN_BYTES; +import static com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController.STORAGE_MIN_BYTES; import static com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController.TERMINAL_PACKAGE_NAME_RESID; import static com.google.common.truth.Truth.assertThat; @@ -29,6 +31,7 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.storage.StorageManager; import org.junit.Before; import org.junit.Test; @@ -43,6 +46,7 @@ public class LinuxTerminalPreferenceControllerTest { @Mock private Context mContext; @Mock private PackageManager mPackageManager; + @Mock private StorageManager mStorageManager; @Mock private PackageInfo mPackageInfo; private String mTerminalPackageName = "com.android.virtualization.terminal"; @@ -57,11 +61,30 @@ public class LinuxTerminalPreferenceControllerTest { doReturn(mPackageInfo) .when(mPackageManager) .getPackageInfo(eq(mTerminalPackageName), anyInt()); + + doReturn(mStorageManager).when(mContext).getSystemService(StorageManager.class); + doReturn(STORAGE_MIN_BYTES).when(mStorageManager).getPrimaryStorageSize(); } @Test - public void isAvailable_whenPackageExists_returnsTrue() throws NameNotFoundException { - mController = new LinuxTerminalPreferenceController(mContext); + public void isAvailable_whenMemoryInsufficient_returnFalse() { + mController = createController(mContext, MEMORY_MIN_BYTES / 2); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_whenDeviceStorageInsufficient_returnFalse() { + doReturn(STORAGE_MIN_BYTES / 2).when(mStorageManager).getPrimaryStorageSize(); + + mController = createController(mContext); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_whenPackageExists_returnsTrue() { + mController = createController(mContext); assertThat(mController.isAvailable()).isTrue(); } @@ -70,7 +93,7 @@ public class LinuxTerminalPreferenceControllerTest { public void isAvailable_whenPackageNameIsNull_returnsFalse() { doReturn(null).when(mContext).getString(TERMINAL_PACKAGE_NAME_RESID); - mController = new LinuxTerminalPreferenceController(mContext); + mController = createController(mContext); assertThat(mController.isAvailable()).isFalse(); } @@ -81,8 +104,21 @@ public class LinuxTerminalPreferenceControllerTest { .when(mPackageManager) .getPackageInfo(eq(mTerminalPackageName), anyInt()); - mController = new LinuxTerminalPreferenceController(mContext); + mController = createController(mContext); assertThat(mController.isAvailable()).isFalse(); } + + private LinuxTerminalPreferenceController createController(Context context) { + return createController(context, MEMORY_MIN_BYTES); + } + + private LinuxTerminalPreferenceController createController(Context context, long totalMemory) { + return new LinuxTerminalPreferenceController(context) { + @Override + public long getTotalMemory() { + return totalMemory; + } + }; + } }