Added transparency-metadata display.

This feature enables 'App Details' to support MBAs with metadata file and display in an offline UI. This change includes a new fragment and user view that sources data from within any MBAs apk file that contains application-metadata.xml.

Test: make -j64 RunSettingsRoboTests , AVD manual test
Change-Id: If7822100a90f5fb8d33ce5d85958391fc33ecbee
Bug: 244215932
This commit is contained in:
George Chan
2022-09-13 19:06:22 +00:00
parent 2286d8c994
commit 9c68bf9312
12 changed files with 897 additions and 20 deletions

View File

@@ -16,6 +16,8 @@
package com.android.settings.applications.appinfo;
import static com.android.settings.applications.mobilebundledapps.MobileBundledAppDetailsActivity.ACTION_TRANSPARENCY_METADATA;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -41,11 +43,14 @@ import android.os.UserManager;
import androidx.preference.Preference;
import com.android.settings.applications.mobilebundledapps.ApplicationMetadataUtils;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -53,7 +58,8 @@ import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class AppInstallerInfoPreferenceControllerTest {
private static final String TEST_PACKAGE_NAME = "Package1";
private static final String TEST_CONTEXT_KEY = "test_key";
@Mock
private UserManager mUserManager;
@Mock
@@ -67,11 +73,17 @@ public class AppInstallerInfoPreferenceControllerTest {
@Mock
private Preference mPreference;
@Mock
private ApplicationMetadataUtils mApplicationMetadataUtils;
@Captor
ArgumentCaptor<Intent> mIntentArgumentCaptor;
private Context mContext;
private AppInstallerInfoPreferenceController mController;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
public void setup() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
@@ -81,9 +93,13 @@ public class AppInstallerInfoPreferenceControllerTest {
when(mInstallSourceInfo.getInstallingPackageName()).thenReturn(installerPackage);
when(mPackageManager.getApplicationInfo(eq(installerPackage), anyInt()))
.thenReturn(mAppInfo);
mController = new AppInstallerInfoPreferenceController(mContext, "test_key");
mController.setPackageName("Package1");
mController = new AppInstallerInfoPreferenceController(mContext, TEST_CONTEXT_KEY);
mController.setParentFragment(mFragment);
mController.setPackageName(TEST_PACKAGE_NAME);
when(mApplicationMetadataUtils.packageContainsXmlFile(mPackageManager, TEST_PACKAGE_NAME))
.thenReturn(false);
mController.setMbaWithMetadataStatus(mApplicationMetadataUtils, TEST_PACKAGE_NAME);
mController.setEnableMbaFlag(true);
}
@Test
@@ -95,8 +111,42 @@ public class AppInstallerInfoPreferenceControllerTest {
}
@Test
public void getAvailabilityStatus_noAppLabel_shouldReturnDisabled() {
public void getAvailabilityStatus_noAppLabel_andNotMbaWithMetadata_shouldReturnDisabled()
throws PackageManager.NameNotFoundException {
when(mUserManager.isManagedProfile()).thenReturn(false);
mockMainlineModule(TEST_PACKAGE_NAME, false /* isMainlineModule */);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_noAppLabel_andHaveMbaFile_shouldReturnAvailable()
throws PackageManager.NameNotFoundException {
mController = new AppInstallerInfoPreferenceController(mContext, TEST_CONTEXT_KEY);
mController.setPackageName(TEST_PACKAGE_NAME);
mController.setParentFragment(mFragment);
when(mApplicationMetadataUtils.packageContainsXmlFile(mPackageManager, TEST_PACKAGE_NAME))
.thenReturn(true);
mController.setMbaWithMetadataStatus(mApplicationMetadataUtils, TEST_PACKAGE_NAME);
mockMainlineModule(TEST_PACKAGE_NAME, false /* isMainlineModule */);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_noAppLabel_andMbaFeatureFlagDisabled_shouldReturnDisabled()
throws PackageManager.NameNotFoundException {
mController.setEnableMbaFlag(false);
when(mUserManager.isManagedProfile()).thenReturn(false);
mController = new AppInstallerInfoPreferenceController(mContext, TEST_CONTEXT_KEY);
mController.setPackageName(TEST_PACKAGE_NAME);
mController.setParentFragment(mFragment);
when(mApplicationMetadataUtils.packageContainsXmlFile(mPackageManager, TEST_PACKAGE_NAME))
.thenReturn(true);
mController.setMbaWithMetadataStatus(mApplicationMetadataUtils, TEST_PACKAGE_NAME);
mockMainlineModule(TEST_PACKAGE_NAME, false /* isMainlineModule */);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.DISABLED_FOR_USER);
@@ -105,13 +155,12 @@ public class AppInstallerInfoPreferenceControllerTest {
@Test
public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable()
throws PackageManager.NameNotFoundException {
final String packageName = "Package1";
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label1");
mController = new AppInstallerInfoPreferenceController(mContext, "test_key");
mController.setPackageName(packageName);
mController = new AppInstallerInfoPreferenceController(mContext, TEST_CONTEXT_KEY);
mController.setPackageName(TEST_PACKAGE_NAME);
mController.setParentFragment(mFragment);
mockMainlineModule(packageName, false /* isMainlineModule */);
mockMainlineModule(TEST_PACKAGE_NAME, false /* isMainlineModule */);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
@@ -129,7 +178,7 @@ public class AppInstallerInfoPreferenceControllerTest {
}
@Test
public void updateState_noAppStoreLink_shouldDisablePreference() {
public void updateState_noAppStoreLink_andNotMbaWithMetadata_shouldDisablePreference() {
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
@@ -139,6 +188,39 @@ public class AppInstallerInfoPreferenceControllerTest {
verify(mPreference).setEnabled(false);
}
@Test
public void updateState_noAppStoreLink_andMbaFeatureFlagDisabled_shouldDisablePreference() {
mController.setEnableMbaFlag(false);
when(mApplicationMetadataUtils.packageContainsXmlFile(mPackageManager, TEST_PACKAGE_NAME))
.thenReturn(true);
mController.setMbaWithMetadataStatus(mApplicationMetadataUtils, TEST_PACKAGE_NAME);
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(null);
mController.updateState(mPreference);
verify(mPreference).setEnabled(false);
}
@Test
public void updateState_noAppStoreLink_andMbaWithMetadata_shouldSetPreferenceIntent() {
when(mApplicationMetadataUtils.packageContainsXmlFile(mPackageManager, TEST_PACKAGE_NAME))
.thenReturn(true);
mController.setMbaWithMetadataStatus(mApplicationMetadataUtils, TEST_PACKAGE_NAME);
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(null);
mController.updateState(mPreference);
verify(mPreference, never()).setEnabled(false);
verify(mPreference).setIntent(mIntentArgumentCaptor.capture());
assertThat(mIntentArgumentCaptor.getValue().getAction())
.isEqualTo(ACTION_TRANSPARENCY_METADATA);
}
@Test
public void updateState_hasAppStoreLink_shouldSetPreferenceIntent() {
@@ -154,7 +236,9 @@ public class AppInstallerInfoPreferenceControllerTest {
mController.updateState(mPreference);
verify(mPreference, never()).setEnabled(false);
verify(mPreference).setIntent(any(Intent.class));
verify(mPreference).setIntent(mIntentArgumentCaptor.capture());
assertThat(mIntentArgumentCaptor.getValue().getAction())
.isEqualTo(Intent.ACTION_SHOW_APP_INFO);
}
@Test

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2022 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.applications.mobilebundledapps;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.when;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.google.common.io.CharSource;
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;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@RunWith(RobolectricTestRunner.class)
public class ApplicationMetadataUtilsTest {
private static final String TEST_PACKAGE_NAME = "test";
private static final String TEST_SOURCE_DIR = "sourcedir";
private static final String TEST_XML_SCHEMA = "<transparency-info>\n"
+ " <template/>\n"
+ " <contains-ads/>\n"
+ " <developers>\n"
+ " <developer name=\"Example ODM\" relationship=\"ODM\" email=\"odm@example.com\""
+ " \n"
+ " website=\"http://odm.example.com\" country=\"US\"/>\n"
+ " <developer name=\"Example carrier\" relationship=\"CARRIER\" "
+ "email=\"carrier@example.com\" \n"
+ " country=\"US\"/>\n"
+ " </developers>\n"
+ " <contact url=\"http://example.com/contact-us\" email=\"contact@example.com\"/>\n"
+ " <privacy-policy url=\"https://www.example.com/privacy-policy.html\"/>\n"
+ " <description>This application provides the user with news "
+ "headlines</description>\n"
+ " <category name=\"News and magazines\"/>\n"
+ "</transparency-info>";
@Mock
private PackageManager mPackageManager;
private Document mDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(CharSource.wrap(TEST_XML_SCHEMA).asByteSource(StandardCharsets.UTF_8)
.openStream());
public ApplicationMetadataUtilsTest()
throws IOException, ParserConfigurationException, SAXException {
}
@Before
public void setup()
throws PackageManager.NameNotFoundException, IOException, ParserConfigurationException,
SAXException {
MockitoAnnotations.initMocks(this);
final ApplicationInfo appInfo = new ApplicationInfo();
appInfo.sourceDir = TEST_SOURCE_DIR;
when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME),
any(PackageManager.ApplicationInfoFlags.class))).thenReturn(appInfo);
}
@Test
public void getDefaultInstance_alwaysReturnSameInstance() {
final ApplicationMetadataUtils firstInstance =
ApplicationMetadataUtils.getDefaultInstance();
assertThat(firstInstance).isEqualTo(ApplicationMetadataUtils.getDefaultInstance());
}
@Test(expected = RuntimeException.class)
public void createInstance_bubblesUpException() throws PackageManager.NameNotFoundException {
final String testErrorMsg = "test";
when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME),
any(PackageManager.ApplicationInfoFlags.class)))
.thenThrow(new Exception(testErrorMsg));
ApplicationMetadataUtils.newInstance(mPackageManager, TEST_PACKAGE_NAME);
}
@Test
public void fieldGetters_toReturnNull_whenEmptyOrError() {
final ApplicationMetadataUtils appUtils = new ApplicationMetadataUtils();
assertThat(appUtils.getContainsAds()).isEqualTo(false);
assertThat(appUtils.getCategoryName()).isNull();
assertThat(appUtils.getPrivacyPolicyUrl()).isNull();
assertThat(appUtils.getDescription()).isNull();
assertThat(appUtils.getDevelopers()).isEmpty();
}
@Test
public void fieldGetters_toReturnCorrectValues_whenExists() {
final ApplicationMetadataUtils appUtils = new ApplicationMetadataUtils();
appUtils.setXmlDoc(mDocument);
assertThat(appUtils.getContainsAds()).isEqualTo(true);
assertThat(appUtils.getCategoryName()).isEqualTo("News and magazines");
assertThat(appUtils.getPrivacyPolicyUrl())
.isEqualTo("https://www.example.com/privacy-policy.html");
assertThat(appUtils.getDescription())
.isEqualTo("This application provides the user with news headlines");
}
@Test
public void getDevelopers_returnsCorrectValues() {
final ApplicationMetadataUtils appUtils = new ApplicationMetadataUtils();
appUtils.setXmlDoc(mDocument);
final List<ApplicationMetadataUtils.MbaDeveloper> developers = appUtils.getDevelopers();
assertThat(developers.size()).isEqualTo(2);
assertThat(developers.get(0).country).isEqualTo("US");
assertThat(developers.get(0).email).isEqualTo("odm@example.com");
assertThat(developers.get(0).name).isEqualTo("Example ODM");
assertThat(developers.get(1).relationship).isEqualTo("CARRIER");
assertThat(developers.get(1).country).isEqualTo("US");
assertThat(developers.get(1).email).isEqualTo("carrier@example.com");
assertThat(developers.get(1).name).isEqualTo("Example carrier");
assertThat(developers.get(1).relationship).isEqualTo("CARRIER");
}
}