Merge "Revert "Added transparency-metadata display.""

This commit is contained in:
George Chan
2022-10-27 18:19:58 +00:00
committed by Android (Google) Code Review
12 changed files with 26 additions and 896 deletions

View File

@@ -56,7 +56,6 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.applications.mobilebundledapps.ApplicationMetadataUtils;
import com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesDetailsPreferenceController;
import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetailPreferenceController;
import com.android.settings.core.SubSettingLauncher;
@@ -163,8 +162,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
use(AppInstallerInfoPreferenceController.class);
installer.setPackageName(packageName);
installer.setParentFragment(this);
installer.setMbaWithMetadataStatus(ApplicationMetadataUtils.getDefaultInstance(),
packageName);
use(AppInstallerPreferenceCategoryController.class).setChildren(Arrays.asList(installer));
use(AppNotificationPreferenceController.class).setParentFragment(this);

View File

@@ -16,50 +16,42 @@
package com.android.settings.applications.appinfo;
import static com.android.settings.applications.mobilebundledapps.MobileBundledAppDetailsActivity.ACTION_TRANSPARENCY_METADATA;
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppStoreUtil;
import com.android.settings.applications.mobilebundledapps.ApplicationMetadataUtils;
import com.android.settingslib.applications.AppUtils;
public class AppInstallerInfoPreferenceController extends AppInfoPreferenceControllerBase {
private static final String KEY_ENABLE_PROMPT = "enable_prompt";
private String mPackageName;
private String mInstallerPackage;
private CharSequence mInstallerLabel;
private Boolean mAppIsMbaWithMetadata;
private Boolean mEnableMbaUiFlag = false;
public AppInstallerInfoPreferenceController(Context context, String key) {
super(context, key);
updateFromDeviceConfigFlags();
}
@Override
public int getAvailabilityStatus() {
if (UserManager.get(mContext).isManagedProfile()
|| AppUtils.isMainlineModule(mContext.getPackageManager(), mPackageName)) {
if (UserManager.get(mContext).isManagedProfile()) {
return DISABLED_FOR_USER;
}
if (mInstallerLabel != null || (mAppIsMbaWithMetadata && mEnableMbaUiFlag)) {
return AVAILABLE;
if (AppUtils.isMainlineModule(mContext.getPackageManager(), mPackageName)) {
return DISABLED_FOR_USER;
}
return DISABLED_FOR_USER;
return mInstallerLabel != null ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
public void updateState(final Preference preference) {
public void updateState(Preference preference) {
final int detailsStringId = AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
? R.string.instant_app_details_summary
: R.string.app_install_details_summary;
@@ -68,52 +60,14 @@ public class AppInstallerInfoPreferenceController extends AppInfoPreferenceContr
Intent intent = AppStoreUtil.getAppStoreLink(mContext, mInstallerPackage, mPackageName);
if (intent != null) {
preference.setIntent(intent);
} else if (mAppIsMbaWithMetadata && mEnableMbaUiFlag) {
preference.setIntent(generateMetadataXmlViewerIntent());
preference.setSummary(mContext.getString(R.string.app_install_details_mba_summary));
} else {
preference.setEnabled(false);
}
}
/**
* Sets the packageName in context for the controller.
*/
public void setPackageName(final String packageName) {
public void setPackageName(String packageName) {
mPackageName = packageName;
mInstallerPackage = AppStoreUtil.getInstallerPackageName(mContext, mPackageName);
mInstallerLabel = Utils.getApplicationLabel(mContext, mInstallerPackage);
}
/**
* Setups and determines if the current package in context is an mobile-bundled-app with
* an application metadata file embedded within.
*/
public void setMbaWithMetadataStatus(final ApplicationMetadataUtils appMetadataUtils,
final String packageName) {
mAppIsMbaWithMetadata = appMetadataUtils.packageContainsXmlFile(
mContext.getPackageManager(), packageName);
}
private Intent generateMetadataXmlViewerIntent() {
final Intent metadataXmlIntent = new Intent(ACTION_TRANSPARENCY_METADATA)
.setPackage(mContext.getPackageName());
metadataXmlIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
return metadataXmlIntent;
}
private void updateFromDeviceConfigFlags() {
String enablePromptFlag = DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_TRANSPARENCY_METADATA,
KEY_ENABLE_PROMPT);
//No-op for empty field and relies on default value of false
if (!TextUtils.isEmpty(enablePromptFlag)) {
setEnableMbaFlag(Boolean.parseBoolean(enablePromptFlag));
}
}
@VisibleForTesting
void setEnableMbaFlag(final boolean flagValue) {
mEnableMbaUiFlag = flagValue;
}
}

View File

@@ -1,201 +0,0 @@
/*
* 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 android.content.pm.PackageManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipFile;
import javax.xml.parsers.DocumentBuilderFactory;
/**
* Used for parsing application-metadata.xml and return relevant fields
*/
public class ApplicationMetadataUtils {
private static final String TAG = ApplicationMetadataUtils.class.getSimpleName();
private static final ApplicationMetadataUtils DEFAULT_INSTANCE = new ApplicationMetadataUtils();
private static final String TRANSPARENCY_XML_DIR = "APP-INF/application-metadata.xml";
private static final String DESCRIPTION_TAG = "description";
private static final String CONTAINS_ADS_TAG = "contains-ads";
private static final String PRIVACY_POLICY_TAG = "privacy-policy";
private static final String CONTACT_TAG = "contact";
private static final String CATEGORY_TAG = "category";
private static final String DEVELOPER_TAG = "developer";
private static final String URL_TAG = "url";
private static final String EMAIL_TAG = "email";
private static final String NAME_TAG = "name";
private static final String RELATIONSHIP_TAG = "relationship";
private static final String COUNTRY_TAG = "country";
private final PackageManager mPackageManager;
private Document mXmlDoc;
@VisibleForTesting
ApplicationMetadataUtils() {
mPackageManager = null;
}
//Need to create singleton factory as Android is unable to mock static for testing.
public static ApplicationMetadataUtils getDefaultInstance() {
return DEFAULT_INSTANCE;
}
/**
* Generates a new instance that also provisions and reads the XML file.
*/
public static ApplicationMetadataUtils newInstance(final PackageManager packageManager,
String packageName) {
return new ApplicationMetadataUtils(packageManager, packageName);
}
private ApplicationMetadataUtils(final PackageManager packageManager,
final String packageName) {
mPackageManager = packageManager;
try (ZipFile apk = new ZipFile(getApkDirectory(packageName, mPackageManager))) {
mXmlDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(apk.getInputStream(apk.getEntry(TRANSPARENCY_XML_DIR)));
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
@VisibleForTesting
void setXmlDoc(final Document xmlDoc) {
mXmlDoc = xmlDoc;
}
private static String getApkDirectory(final String packageName,
final PackageManager packageManager)
throws PackageManager.NameNotFoundException {
return packageManager
.getApplicationInfo(packageName,
PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA))
.sourceDir;
}
public boolean getContainsAds() {
return mXmlDoc != null
&& mXmlDoc.getElementsByTagName(CONTAINS_ADS_TAG) != null
&& mXmlDoc.getElementsByTagName(CONTAINS_ADS_TAG).getLength() > 0;
}
public String getPrivacyPolicyUrl() {
return retrieveElementAttributeValue(PRIVACY_POLICY_TAG, URL_TAG);
}
private String retrieveElementAttributeValue(final String elementTag, final String attribute) {
try {
return mXmlDoc.getElementsByTagName(elementTag).item(0)
.getAttributes().getNamedItem(attribute).getNodeValue();
} catch (Exception e) {
return null;
}
}
public String getDescription() {
return retrieveElementValue(DESCRIPTION_TAG);
}
private String retrieveElementValue(final String elementTag) {
try {
return mXmlDoc.getElementsByTagName(elementTag).item(0).getTextContent();
} catch (Exception e) {
return null;
}
}
public String getCategoryName() {
return retrieveElementAttributeValue(CATEGORY_TAG, NAME_TAG);
}
public String getContactUrl() {
return retrieveElementAttributeValue(CONTACT_TAG, URL_TAG);
}
public String getContactEmail() {
return retrieveElementAttributeValue(CONTACT_TAG, EMAIL_TAG);
}
public String getPlayStoreUrl() {
return retrieveElementValue(DESCRIPTION_TAG);
}
/**
* Retrieves the list of relevant major parties involved with this MBA
*/
public List<MbaDeveloper> getDevelopers() {
final List<MbaDeveloper> developersDetails = new ArrayList();
try {
final NodeList developers = mXmlDoc.getElementsByTagName(DEVELOPER_TAG);
if (developers == null) return developersDetails;
for (int i = 0; i < developers.getLength(); ++i) {
final NamedNodeMap developerAttributes = developers.item(i).getAttributes();
developersDetails.add(new MbaDeveloper(
developerAttributes.getNamedItem(NAME_TAG).getNodeValue(),
developerAttributes.getNamedItem(RELATIONSHIP_TAG).getNodeValue(),
developerAttributes.getNamedItem(EMAIL_TAG).getNodeValue(),
developerAttributes.getNamedItem(COUNTRY_TAG).getNodeValue()
));
}
} catch (final Exception e) {
Log.d(TAG, e.getMessage());
}
return developersDetails;
}
/**
* Determines if the a package can be parsed and extrapolate metadata from.
*/
public boolean packageContainsXmlFile(final PackageManager packageManager,
final String packageName) {
try (ZipFile apk = new ZipFile(getApkDirectory(packageName, packageManager))) {
return apk.getEntry(TRANSPARENCY_XML_DIR) != null;
} catch (final Exception e) {
Log.d(TAG, e.getMessage());
return false;
}
}
/**
* Used to return developer details
*/
public static class MbaDeveloper {
public final String name;
public final String relationship;
public final String email;
public final String country;
public MbaDeveloper(final String name,
final String relationship,
final String email,
final String country) {
this.name = name;
this.relationship = relationship;
this.email = email;
this.country = country;
}
}
}

View File

@@ -1,47 +0,0 @@
/*
* 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 android.content.Intent;
import android.net.Uri;
import com.android.settings.SettingsActivity;
/**
* An activity that is used to parse and display mobile-bundled apps application metadata xml file.
*/
public class MobileBundledAppDetailsActivity extends SettingsActivity {
public static final String ACTION_TRANSPARENCY_METADATA =
"android.settings.TRANSPARENCY_METADATA";
public MobileBundledAppDetailsActivity() {
super();
}
@Override
public Intent getIntent() {
final Intent modIntent = new Intent(super.getIntent());
modIntent.setData(Uri.parse("package:"
+ super.getIntent().getExtra(Intent.EXTRA_PACKAGE_NAME).toString()));
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, MobileBundledAppsDetailsFragment.class.getName());
return modIntent;
}
@Override
protected boolean isValidFragment(final String fragmentName) {
return MobileBundledAppsDetailsFragment.class.getName().equals(fragmentName);
}
}

View File

@@ -1,133 +0,0 @@
/*
* 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 android.app.Application;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
import com.android.settings.applications.AppInfoWithHeader;
import com.android.settings.applications.mobilebundledapps.ApplicationMetadataUtils.MbaDeveloper;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.widget.LayoutPreference;
import java.util.List;
/**
* A fragment for retrieving the transparency metadata and PSL in the in-APK XML file and displaying
* them.
*/
public class MobileBundledAppsDetailsFragment extends AppInfoWithHeader {
private static final String METADATA_PREF_KEY = "metadata";
protected PackageManager mPackageManager;
private Context mContext;
private LayoutPreference mMetadataPreferenceView;
private ApplicationsState mApplicationState;
private boolean mCreated = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
mPackageManager = mContext.getPackageManager();
addPreferencesFromResource(R.xml.mobile_bundled_apps_details_preference);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if (mCreated) {
return;
}
super.onActivityCreated(savedInstanceState);
final ApplicationMetadataUtils appUtil = ApplicationMetadataUtils.newInstance(
mPackageManager,
mPackageName);
if (mAppEntry == null) {
mApplicationState =
ApplicationsState.getInstance((Application) (mContext.getApplicationContext()));
mAppEntry = mApplicationState.getEntry(mPackageName, mContext.getUserId());
}
mMetadataPreferenceView = findPreference(METADATA_PREF_KEY);
createView(appUtil);
mCreated = true;
}
private void createView(final ApplicationMetadataUtils appUtil) {
final LinearLayout devListLayout =
mMetadataPreferenceView.findViewById(R.id.developer_list);
populateDeveloperList(appUtil.getDevelopers(), devListLayout);
((TextView) mMetadataPreferenceView.findViewById(R.id.contains_ads))
.setText(Boolean.toString(appUtil.getContainsAds()));
((TextView) mMetadataPreferenceView.findViewById(R.id.contact_url))
.setText(appUtil.getContactUrl());
((TextView) mMetadataPreferenceView.findViewById(R.id.contact_email))
.setText(appUtil.getContactEmail());
((TextView) mMetadataPreferenceView.findViewById(R.id.privacy_policy_url))
.setText(appUtil.getPrivacyPolicyUrl());
((TextView) mMetadataPreferenceView.findViewById(R.id.description))
.setText(appUtil.getDescription());
((TextView) mMetadataPreferenceView.findViewById(R.id.category))
.setText(appUtil.getCategoryName());
}
private void populateDeveloperList(List<MbaDeveloper> developersDetails, ViewGroup parent) {
for (MbaDeveloper dev : developersDetails) {
View itemView = LayoutInflater.from(mContext)
.inflate(R.layout.mobile_bundled_apps_developer_fragment_row, parent, false);
((TextView) itemView.findViewById(R.id.developer_name)).setText(dev.name);
((TextView) itemView.findViewById(R.id.developer_relationship))
.setText(dev.relationship);
((TextView) itemView.findViewById(R.id.developer_email)).setText(dev.email);
((TextView) itemView.findViewById(R.id.developer_country)).setText(dev.country);
parent.addView(itemView);
}
}
@Override
protected AlertDialog createDialog(int id, int errorCode) {
return null;
}
@Override
protected boolean refreshUi() {
return true;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.TRANSPARENCY_METADATA;
}
}