Merge "[Mainline] Copy the findBestComponent method from EuiccConnector to Settings"
This commit is contained in:
@@ -16,24 +16,30 @@
|
|||||||
|
|
||||||
package com.android.settings.applications;
|
package com.android.settings.applications;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.ComponentInfo;
|
import android.content.pm.ComponentInfo;
|
||||||
import android.content.pm.IPackageManager;
|
import android.content.pm.IPackageManager;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.content.pm.ServiceInfo;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.service.euicc.EuiccService;
|
||||||
import android.telecom.DefaultDialerManager;
|
import android.telecom.DefaultDialerManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.internal.telephony.SmsApplication;
|
import com.android.internal.telephony.SmsApplication;
|
||||||
import com.android.internal.telephony.euicc.EuiccConnector;
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -41,12 +47,17 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvider {
|
public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvider {
|
||||||
|
private static final String TAG = "AppFeatureProviderImpl";
|
||||||
|
|
||||||
protected final Context mContext;
|
protected final Context mContext;
|
||||||
private final PackageManager mPm;
|
private final PackageManager mPm;
|
||||||
private final IPackageManager mPms;
|
private final IPackageManager mPms;
|
||||||
private final DevicePolicyManager mDpm;
|
private final DevicePolicyManager mDpm;
|
||||||
private final UserManager mUm;
|
private final UserManager mUm;
|
||||||
|
/** Flags to use when querying PackageManager for Euicc component implementations. */
|
||||||
|
private static final int EUICC_QUERY_FLAGS =
|
||||||
|
PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
|
||||||
|
| PackageManager.GET_RESOLVED_FILTER;
|
||||||
|
|
||||||
public ApplicationFeatureProviderImpl(Context context, PackageManager pm,
|
public ApplicationFeatureProviderImpl(Context context, PackageManager pm,
|
||||||
IPackageManager pms, DevicePolicyManager dpm) {
|
IPackageManager pms, DevicePolicyManager dpm) {
|
||||||
@@ -143,7 +154,7 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keep Euicc Service enabled.
|
// Keep Euicc Service enabled.
|
||||||
final ComponentInfo euicc = EuiccConnector.findBestComponent(mPm);
|
final ComponentInfo euicc = findEuiccService(mPm);
|
||||||
if (euicc != null) {
|
if (euicc != null) {
|
||||||
keepEnabledPackages.add(euicc.packageName);
|
keepEnabledPackages.add(euicc.packageName);
|
||||||
}
|
}
|
||||||
@@ -239,4 +250,89 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
|
|||||||
mCallback.onListOfAppsResult(list);
|
mCallback.onListOfAppsResult(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the component info of the EuiccService to bind to, or null if none were found.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
ComponentInfo findEuiccService(PackageManager packageManager) {
|
||||||
|
final Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE);
|
||||||
|
final List<ResolveInfo> resolveInfoList =
|
||||||
|
packageManager.queryIntentServices(intent, EUICC_QUERY_FLAGS);
|
||||||
|
final ComponentInfo bestComponent = findEuiccService(packageManager, resolveInfoList);
|
||||||
|
if (bestComponent == null) {
|
||||||
|
Log.w(TAG, "No valid EuiccService implementation found");
|
||||||
|
}
|
||||||
|
return bestComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComponentInfo findEuiccService(
|
||||||
|
PackageManager packageManager, List<ResolveInfo> resolveInfoList) {
|
||||||
|
int bestPriority = Integer.MIN_VALUE;
|
||||||
|
ComponentInfo bestComponent = null;
|
||||||
|
if (resolveInfoList != null) {
|
||||||
|
for (ResolveInfo resolveInfo : resolveInfoList) {
|
||||||
|
if (!isValidEuiccComponent(packageManager, resolveInfo)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolveInfo.filter.getPriority() > bestPriority) {
|
||||||
|
bestPriority = resolveInfo.filter.getPriority();
|
||||||
|
bestComponent = getComponentInfo(resolveInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidEuiccComponent(
|
||||||
|
PackageManager packageManager, ResolveInfo resolveInfo) {
|
||||||
|
final ComponentInfo componentInfo = getComponentInfo(resolveInfo);
|
||||||
|
final String packageName = componentInfo.packageName;
|
||||||
|
|
||||||
|
// Verify that the app is privileged (via granting of a privileged permission).
|
||||||
|
if (packageManager.checkPermission(
|
||||||
|
Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
Log.e(TAG, "Package " + packageName
|
||||||
|
+ " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that only the system can access the component.
|
||||||
|
final String permission;
|
||||||
|
if (componentInfo instanceof ServiceInfo) {
|
||||||
|
permission = ((ServiceInfo) componentInfo).permission;
|
||||||
|
} else if (componentInfo instanceof ActivityInfo) {
|
||||||
|
permission = ((ActivityInfo) componentInfo).permission;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Can only verify services/activities");
|
||||||
|
}
|
||||||
|
if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) {
|
||||||
|
Log.e(TAG, "Package " + packageName
|
||||||
|
+ " does not require the BIND_EUICC_SERVICE permission");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the component declares a priority.
|
||||||
|
if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) {
|
||||||
|
Log.e(TAG, "Package " + packageName + " does not specify a priority");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComponentInfo getComponentInfo(ResolveInfo resolveInfo) {
|
||||||
|
if (resolveInfo.activityInfo != null) {
|
||||||
|
return resolveInfo.activityInfo;
|
||||||
|
}
|
||||||
|
if (resolveInfo.serviceInfo != null) {
|
||||||
|
return resolveInfo.serviceInfo;
|
||||||
|
}
|
||||||
|
if (resolveInfo.providerInfo != null) {
|
||||||
|
return resolveInfo.providerInfo;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Missing ComponentInfo!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.applications;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -37,12 +38,10 @@ import android.os.Build;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
|
||||||
import com.android.internal.telephony.euicc.EuiccConnector;
|
|
||||||
import com.android.settings.testutils.ApplicationTestUtils;
|
import com.android.settings.testutils.ApplicationTestUtils;
|
||||||
import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
|
import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
|
||||||
import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
|
import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -51,8 +50,6 @@ import org.mockito.MockitoAnnotations;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.annotation.Implementation;
|
|
||||||
import org.robolectric.annotation.Implements;
|
|
||||||
import org.robolectric.shadows.ShadowApplication;
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
import org.robolectric.util.ReflectionHelpers;
|
import org.robolectric.util.ReflectionHelpers;
|
||||||
|
|
||||||
@@ -109,12 +106,6 @@ public final class ApplicationFeatureProviderImplTest {
|
|||||||
mPackageManagerService, mDevicePolicyManager);
|
mPackageManagerService, mDevicePolicyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
@Config(shadows = {ShadowEuiccConnector.class})
|
|
||||||
public void tearDown() {
|
|
||||||
ShadowEuiccConnector.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyCalculateNumberOfPolicyInstalledApps(boolean async) {
|
private void verifyCalculateNumberOfPolicyInstalledApps(boolean async) {
|
||||||
setUpUsersAndInstalledApps();
|
setUpUsersAndInstalledApps();
|
||||||
|
|
||||||
@@ -293,8 +284,7 @@ public final class ApplicationFeatureProviderImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class,
|
@Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class})
|
||||||
ShadowEuiccConnector.class})
|
|
||||||
public void getKeepEnabledPackages_hasEuiccComponent_shouldContainEuiccPackage() {
|
public void getKeepEnabledPackages_hasEuiccComponent_shouldContainEuiccPackage() {
|
||||||
final String testDialer = "com.android.test.defaultdialer";
|
final String testDialer = "com.android.test.defaultdialer";
|
||||||
final String testSms = "com.android.test.defaultsms";
|
final String testSms = "com.android.test.defaultsms";
|
||||||
@@ -305,7 +295,10 @@ public final class ApplicationFeatureProviderImplTest {
|
|||||||
ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
|
ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
|
||||||
final ComponentInfo componentInfo = new ComponentInfo();
|
final ComponentInfo componentInfo = new ComponentInfo();
|
||||||
componentInfo.packageName = testEuicc;
|
componentInfo.packageName = testEuicc;
|
||||||
ShadowEuiccConnector.setBestComponent(componentInfo);
|
|
||||||
|
ApplicationFeatureProviderImpl spyProvider = spy(new ApplicationFeatureProviderImpl(
|
||||||
|
mContext, mPackageManager, mPackageManagerService, mDevicePolicyManager));
|
||||||
|
doReturn(componentInfo).when(spyProvider).findEuiccService(mPackageManager);
|
||||||
|
|
||||||
// Spy the real context to mock LocationManager.
|
// Spy the real context to mock LocationManager.
|
||||||
Context spyContext = spy(RuntimeEnvironment.application);
|
Context spyContext = spy(RuntimeEnvironment.application);
|
||||||
@@ -314,7 +307,7 @@ public final class ApplicationFeatureProviderImplTest {
|
|||||||
|
|
||||||
ReflectionHelpers.setField(mProvider, "mContext", spyContext);
|
ReflectionHelpers.setField(mProvider, "mContext", spyContext);
|
||||||
|
|
||||||
final Set<String> keepEnabledPackages = mProvider.getKeepEnabledPackages();
|
final Set<String> keepEnabledPackages = spyProvider.getKeepEnabledPackages();
|
||||||
|
|
||||||
assertThat(keepEnabledPackages).contains(testEuicc);
|
assertThat(keepEnabledPackages).contains(testEuicc);
|
||||||
}
|
}
|
||||||
@@ -391,23 +384,4 @@ public final class ApplicationFeatureProviderImplTest {
|
|||||||
resolveInfo.activityInfo = activityInfo;
|
resolveInfo.activityInfo = activityInfo;
|
||||||
return resolveInfo;
|
return resolveInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Implements(EuiccConnector.class)
|
|
||||||
public static class ShadowEuiccConnector {
|
|
||||||
|
|
||||||
private static ComponentInfo sBestComponent;
|
|
||||||
|
|
||||||
@Implementation
|
|
||||||
protected static ComponentInfo findBestComponent(PackageManager packageManager) {
|
|
||||||
return sBestComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setBestComponent(ComponentInfo componentInfo) {
|
|
||||||
sBestComponent = componentInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reset() {
|
|
||||||
sBestComponent = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user