Merge "Revert "Added transparency-metadata display.""
This commit is contained in:
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user