| /* |
| * Copyright (C) 2011 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 android.app.cts; |
| |
| import android.app.Activity; |
| import android.app.ActivityManager; |
| import android.app.stubs.ActivityManagerMemoryClassLaunchActivity; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.PackageManager; |
| import android.content.res.Configuration; |
| import android.graphics.Insets; |
| import android.test.ActivityInstrumentationTestCase2; |
| import android.util.DisplayMetrics; |
| import android.util.Log; |
| import android.view.Display; |
| import android.view.WindowInsets; |
| import android.view.WindowManager; |
| |
| import androidx.test.uiautomator.UiDevice; |
| |
| import com.android.compatibility.common.util.CddTest; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * {@link ActivityInstrumentationTestCase2} that tests {@link ActivityManager#getMemoryClass()} |
| * by checking that the memory class matches the proper screen density and by launching an |
| * application that attempts to allocate memory on the heap. |
| */ |
| public class ActivityManagerMemoryClassTest |
| extends ActivityInstrumentationTestCase2<ActivityManagerMemoryClassLaunchActivity> { |
| |
| public ActivityManagerMemoryClassTest() { |
| super(ActivityManagerMemoryClassLaunchActivity.class); |
| } |
| |
| public static class ExpectedMemorySizesClass { |
| private static final Map<Integer, Integer> expectedMemorySizeForWatch |
| = new HashMap<Integer, Integer>(); |
| private static final Map<Integer, Integer> expectedMemorySizeForSmallNormalScreen |
| = new HashMap<Integer, Integer>(); |
| private static final Map<Integer, Integer> expectedMemorySizeForLargeScreen |
| = new HashMap<Integer, Integer>(); |
| private static final Map<Integer, Integer> expectedMemorySizeForXLargeScreen |
| = new HashMap<Integer, Integer>(); |
| |
| static { |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_LOW, 32); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_140, 32); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_MEDIUM, 32); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_180, 32); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_200, 32); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_TV, 32); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_220, 36); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_HIGH, 36); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_260, 36); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_280, 36); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_300, 36); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XHIGH, 48); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_340, 48); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_360, 48); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_390, 48); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_400, 56); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_420, 64); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_440, 88); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_450, 88); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXHIGH, 88); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_520, 112); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_560, 112); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_600, 138); |
| expectedMemorySizeForWatch.put(DisplayMetrics.DENSITY_XXXHIGH, 154); |
| // Backport of DENSITY_520 from Android 14 to android13-tests-dev |
| expectedMemorySizeForWatch.put(520, 112); |
| // Backport of DENSITY_390 to android14-tests-dev |
| expectedMemorySizeForWatch.put(390, 48); |
| } |
| |
| static { |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_LOW, 32); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_140, 32); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_MEDIUM, 32); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_180, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_200, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_TV, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_220, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_HIGH, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_260, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_280, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_300, 48); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XHIGH, 80); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_340, 80); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 80); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_390, 80); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_400, 96); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_420, 112); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_440, 128); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_450, 128); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXHIGH, 128); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_520, 192); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_560, 192); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_600, 228); |
| expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 256); |
| // Backport of DENSITY_520 from Android 14 to android13-tests-dev |
| expectedMemorySizeForSmallNormalScreen.put(520, 192); |
| // Backport of DENSITY_390 to android14-tests-dev |
| expectedMemorySizeForSmallNormalScreen.put(390, 80); |
| } |
| |
| static { |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_LOW, 32); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_140, 48); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_MEDIUM, 48); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_180, 80); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_200, 80); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_TV, 80); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_220, 80); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_HIGH, 80); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_260, 96); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_280, 96); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_300, 96); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 128); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_340, 160); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_360, 160); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_390, 160); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_400, 192); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_420, 228); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_440, 256); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_450, 256); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 256); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_520, 384); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_560, 384); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_600, 448); |
| expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 512); |
| // Backport of DENSITY_520 from Android 14 to android13-tests-dev |
| expectedMemorySizeForLargeScreen.put(520, 192); |
| // Backport of DENSITY_390 to android14-tests-dev |
| expectedMemorySizeForLargeScreen.put(390, 160); |
| } |
| |
| static { |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_LOW, 48); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_140, 80); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_MEDIUM, 80); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_180, 96); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_200, 96); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_TV, 96); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_220, 96); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_HIGH, 96); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_260, 144); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_280, 144); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_300, 144); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 192); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_340, 192); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_360, 240); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_390, 240); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_400, 288); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_420, 336); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_440, 384); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_450, 384); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 384); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_520, 576); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_560, 576); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_600, 672); |
| expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768); |
| // Backport of DENSITY_520 from Android 14 to android13-tests-dev |
| expectedMemorySizeForXLargeScreen.put(520, 576); |
| // Backport of DENSITY_390 to android14-tests-dev |
| expectedMemorySizeForXLargeScreen.put(390, 240); |
| } |
| |
| public static Integer getExpectedMemorySize( |
| int screenSize, |
| int screenDensity, |
| boolean isWatch) { |
| |
| if (isWatch) { |
| return expectedMemorySizeForWatch.get(screenDensity); |
| } |
| |
| switch (screenSize) { |
| case Configuration.SCREENLAYOUT_SIZE_SMALL: |
| case Configuration.SCREENLAYOUT_SIZE_NORMAL: |
| return expectedMemorySizeForSmallNormalScreen.get(screenDensity); |
| case Configuration.SCREENLAYOUT_SIZE_LARGE: |
| return expectedMemorySizeForLargeScreen.get(screenDensity); |
| case Configuration.SCREENLAYOUT_SIZE_XLARGE: |
| return expectedMemorySizeForXLargeScreen.get(screenDensity); |
| default: |
| throw new IllegalArgumentException("No memory requirement specified " |
| + " for screen layout size " + screenSize); |
| } |
| } |
| } |
| |
| @CddTest(requirement="3.7") |
| public void testGetMemoryClass() throws Exception { |
| UiDevice uiDevice = UiDevice.getInstance(getInstrumentation()); |
| int density = resetDensityIfNeeded(uiDevice); |
| |
| int memoryClass = getMemoryClass(); |
| int screenDensity = getScreenDensity(); |
| int screenSize = getScreenSize(); |
| assertMemoryForScreenDensity(memoryClass, screenDensity, screenSize); |
| |
| runHeapTestApp(memoryClass); |
| |
| restoreDensityIfNeeded(uiDevice, density); |
| } |
| |
| private int resetDensityIfNeeded(UiDevice device) throws Exception { |
| final String output = device.executeShellCommand("wm density"); |
| final Pattern p = Pattern.compile("Override density: (\\d+)"); |
| final Matcher m = p.matcher(output); |
| if (m.find()) { |
| device.executeShellCommand("wm density reset"); |
| int restoreDensity = Integer.parseInt(m.group(1)); |
| return restoreDensity; |
| } |
| return -1; |
| } |
| |
| private void restoreDensityIfNeeded(UiDevice device, int restoreDensity) throws Exception { |
| if (restoreDensity > 0) { |
| device.executeShellCommand("wm density " + restoreDensity); |
| } |
| } |
| |
| private int getMemoryClass() { |
| Context context = getInstrumentation().getTargetContext(); |
| ActivityManager activityManager = |
| (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
| return activityManager.getMemoryClass(); |
| } |
| |
| private int getScreenDensity() { |
| Context context = getInstrumentation().getTargetContext(); |
| WindowManager windowManager = |
| (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); |
| Display display = windowManager.getDefaultDisplay(); |
| DisplayMetrics metrics = new DisplayMetrics(); |
| display.getMetrics(metrics); |
| return metrics.densityDpi; |
| } |
| |
| private int getScreenSize() { |
| Context context = getInstrumentation().getTargetContext(); |
| Configuration config = context.getResources().getConfiguration(); |
| final int configScreenSize = config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK; |
| final int minScreenSizeDp = Math.min(config.screenWidthDp, config.screenHeightDp); |
| // The insets size may affect screenSizeDp in different orientations. E.g., the short side |
| // is 720dp as the width in portrait orientation, but when the short side is the height in |
| // landscape orientation, the value will be smaller than 720dp because the insets of |
| // system bars may occupy a little space. Then the screen size from Configuration will be |
| // LARGE in landscape and XLARGE in portrait. So below calculation allows to return a |
| // smaller size definition if the size excluding insets is lower than the size threshold. |
| final Insets insets = getActivity().getWindowManager().getCurrentWindowMetrics() |
| .getWindowInsets().getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()); |
| final int insetsSize = Math.max(insets.top + insets.bottom, insets.left + insets.right); |
| final int toleranceSizeDp = (int) (insetsSize / |
| ((float) config.densityDpi / DisplayMetrics.DENSITY_DEFAULT) + 0.5f); |
| Log.i("ActivityManagerMemoryClassTest", "getScreenSize: config=" + config |
| + " insets=" + insets + " toleranceSizeDp=" + toleranceSizeDp); |
| if (configScreenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE |
| && (minScreenSizeDp - toleranceSizeDp < 720)) { |
| return Configuration.SCREENLAYOUT_SIZE_LARGE; |
| } |
| if (configScreenSize == Configuration.SCREENLAYOUT_SIZE_LARGE |
| && (minScreenSizeDp - toleranceSizeDp < 480)) { |
| return Configuration.SCREENLAYOUT_SIZE_NORMAL; |
| } |
| return configScreenSize; |
| } |
| |
| private void assertMemoryForScreenDensity(int memoryClass, int screenDensity, int screenSize) { |
| Context context = getInstrumentation().getTargetContext(); |
| boolean isWatch = |
| context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); |
| int expectedMinimumMemory = |
| ExpectedMemorySizesClass.getExpectedMemorySize(screenSize, screenDensity, isWatch); |
| |
| assertTrue("Expected to have at least " + expectedMinimumMemory |
| + "mb of memory for screen density " + screenDensity, |
| memoryClass >= expectedMinimumMemory); |
| } |
| |
| private void runHeapTestApp(int memoryClass) throws InterruptedException { |
| Intent intent = new Intent(); |
| intent.putExtra(ActivityManagerMemoryClassLaunchActivity.MEMORY_CLASS_EXTRA, |
| memoryClass); |
| setActivityIntent(intent); |
| ActivityManagerMemoryClassLaunchActivity activity = getActivity(); |
| assertEquals("The test application couldn't allocate memory close to the amount " |
| + " specified by the memory class.", Activity.RESULT_OK, activity.getResult()); |
| } |
| } |