summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHai Zhang <zhanghai@google.com>2018-12-18 16:52:56 -0800
committerHai Zhang <zhanghai@google.com>2019-01-02 15:17:42 -0800
commitd2e1c217e68062ce8db204368d5005666eaa803c (patch)
treec73f9803183657216e54accf928648a3e4cc9e6e
parent316e8d80355a0ed19fe2666a8a26a90c9040855e (diff)
downloadandroid_packages_apps_PackageInstaller-d2e1c217e68062ce8db204368d5005666eaa803c.tar.gz
android_packages_apps_PackageInstaller-d2e1c217e68062ce8db204368d5005666eaa803c.tar.bz2
android_packages_apps_PackageInstaller-d2e1c217e68062ce8db204368d5005666eaa803c.zip
Add availabilityProvider attribute for roles.
This change adds a new availabilityProvider attribute for roles, thus allowing the dialer and SMS role availability to work as before. Bug: 110557011 Test: build Change-Id: I03b7ba56189f549fb2326582e43628dbc9beebdf
-rw-r--r--proguard.flags5
-rw-r--r--res/xml/roles.xml12
-rw-r--r--src/com/android/packageinstaller/role/model/DialerRoleAvailabilityProvider.java38
-rw-r--r--src/com/android/packageinstaller/role/model/Role.java96
-rw-r--r--src/com/android/packageinstaller/role/model/RoleAvailabilityProvider.java38
-rw-r--r--src/com/android/packageinstaller/role/model/Roles.java26
-rw-r--r--src/com/android/packageinstaller/role/model/SmsRoleAvailabilityProvider.java50
-rw-r--r--src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java27
-rw-r--r--src/com/android/packageinstaller/role/ui/DefaultAppActivity.java5
-rw-r--r--src/com/android/packageinstaller/role/ui/RequestRoleActivity.java6
-rw-r--r--src/com/android/packageinstaller/role/ui/RoleListLiveData.java4
11 files changed, 276 insertions, 31 deletions
diff --git a/proguard.flags b/proguard.flags
index 46a929e3..05defe97 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -6,3 +6,8 @@
*;
}
-dontwarn androidx.core.**
+
+# Keep classes that implements RoleAvailabilityProvider, which are used by reflection.
+-keep class * implements com.android.packageinstaller.role.model.RoleAvailabilityProvider {
+ *;
+}
diff --git a/res/xml/roles.xml b/res/xml/roles.xml
index 454f405b..1fca6dcb 100644
--- a/res/xml/roles.xml
+++ b/res/xml/roles.xml
@@ -147,7 +147,11 @@
</role>
<!--- @see android.telecom.DefaultDialerManager -->
- <role name="android.app.role.DIALER" exclusive="true" label="@string/role_label_dialer">
+ <role
+ name="android.app.role.DIALER"
+ availabilityProvider="DialerRoleAvailabilityProvider"
+ exclusive="true"
+ label="@string/role_label_dialer">
<required-components>
<activity>
<intent-filter>
@@ -196,7 +200,11 @@
</role>
<!--- @see com.android.internal.telephony.SmsApplication -->
- <role name="android.app.role.SMS" exclusive="true" label="@string/role_label_sms">
+ <role
+ name="android.app.role.SMS"
+ availabilityProvider="SmsRoleAvailabilityProvider"
+ exclusive="true"
+ label="@string/role_label_sms">
<required-components>
<receiver permission="android.permission.BROADCAST_SMS">
<intent-filter>
diff --git a/src/com/android/packageinstaller/role/model/DialerRoleAvailabilityProvider.java b/src/com/android/packageinstaller/role/model/DialerRoleAvailabilityProvider.java
new file mode 100644
index 00000000..9638bc8f
--- /dev/null
+++ b/src/com/android/packageinstaller/role/model/DialerRoleAvailabilityProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.packageinstaller.role.model;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Class for determining whether the dialer role is available.
+ *
+ * @see com.android.settings.applications.DefaultAppSettings
+ * @see com.android.settings.applications.defaultapps.DefaultPhonePreferenceController#isAvailable()
+ */
+public class DialerRoleAvailabilityProvider implements RoleAvailabilityProvider {
+
+ @Override
+ public boolean isRoleAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) {
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ return telephonyManager.isVoiceCapable();
+ }
+}
diff --git a/src/com/android/packageinstaller/role/model/Role.java b/src/com/android/packageinstaller/role/model/Role.java
index 2ea8d462..cfe627ea 100644
--- a/src/com/android/packageinstaller/role/model/Role.java
+++ b/src/com/android/packageinstaller/role/model/Role.java
@@ -21,11 +21,13 @@ import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.os.Process;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.android.packageinstaller.role.utils.PackageUtils;
@@ -63,10 +65,10 @@ public class Role {
private final String mName;
/**
- * The string resource for the label of this role.
+ * Whether this role is available in managed profile, i.e. work profile.
*/
- @StringRes
- private final int mLabelResource;
+ @Nullable
+ private final RoleAvailabilityProvider mAvailabilityProvider;
/**
* Whether this role is exclusive, i.e. allows at most one holder.
@@ -74,6 +76,12 @@ public class Role {
private final boolean mExclusive;
/**
+ * The string resource for the label of this role.
+ */
+ @StringRes
+ private final int mLabelResource;
+
+ /**
* The required components for an application to qualify for this role.
*/
@NonNull
@@ -97,12 +105,14 @@ public class Role {
@NonNull
private final List<PreferredActivity> mPreferredActivities;
- public Role(@NonNull String name, @StringRes int labelResource, boolean exclusive,
+ public Role(@NonNull String name, @Nullable RoleAvailabilityProvider availabilityProvider,
+ boolean exclusive, @StringRes int labelResource,
@NonNull List<RequiredComponent> requiredComponents, @NonNull List<String> permissions,
@NonNull List<AppOp> appOps, @NonNull List<PreferredActivity> preferredActivities) {
mName = name;
- mLabelResource = labelResource;
+ mAvailabilityProvider = availabilityProvider;
mExclusive = exclusive;
+ mLabelResource = labelResource;
mRequiredComponents = requiredComponents;
mPermissions = permissions;
mAppOps = appOps;
@@ -114,15 +124,20 @@ public class Role {
return mName;
}
- @StringRes
- public int getLabelResource() {
- return mLabelResource;
+ @Nullable
+ public RoleAvailabilityProvider getAvailabilityProvider() {
+ return mAvailabilityProvider;
}
public boolean isExclusive() {
return mExclusive;
}
+ @StringRes
+ public int getLabelResource() {
+ return mLabelResource;
+ }
+
@NonNull
public List<RequiredComponent> getRequiredComponents() {
return mRequiredComponents;
@@ -144,6 +159,32 @@ public class Role {
}
/**
+ * Check whether this role is available.
+ *
+ * @param user the user to check for
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return whether this role is available.
+ */
+ public boolean isAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) {
+ if (mAvailabilityProvider != null) {
+ return mAvailabilityProvider.isRoleAvailableAsUser(user, context);
+ }
+ return true;
+ }
+
+ /**
+ * Check whether this role is available, for current user.
+ *
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return whether this role is available.
+ */
+ public boolean isAvailable(@NonNull Context context) {
+ return isAvailableAsUser(Process.myUserHandle(), context);
+ }
+
+ /**
* Check whether a package is qualified for this role, i.e. whether it contains all the required
* components.
*
@@ -270,30 +311,31 @@ public class Role {
*/
public void revoke(@NonNull String packageName, boolean mayKillApp,
boolean overrideSystemFixedPermissions, @NonNull Context context) {
- List<String> remainingRolesHeld = context.getSystemService(RoleManager.class)
- .getHeldRolesFromController(packageName);
- remainingRolesHeld.remove(mName);
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ List<String> otherRoleNames = roleManager.getHeldRolesFromController(packageName);
+ otherRoleNames.remove(mName);
- // Revoke permissions
- ArrayMap<String, Role> roles = Roles.getRoles(context);
List<String> permissionsToRevoke = new ArrayList<>(mPermissions);
- int size = remainingRolesHeld.size();
- for (int i = 0; i < size; i++) {
- String remainingRole = remainingRolesHeld.get(i);
- permissionsToRevoke.removeAll(roles.get(remainingRole).getPermissions());
+ ArrayMap<String, Role> roles = Roles.getRoles(context);
+ int otherRoleNamesSize = otherRoleNames.size();
+ for (int i = 0; i < otherRoleNamesSize; i++) {
+ String roleName = otherRoleNames.get(i);
+ Role role = roles.get(roleName);
+ permissionsToRevoke.removeAll(role.getPermissions());
}
boolean permissionOrAppOpChanged = Permissions.revoke(packageName, permissionsToRevoke,
overrideSystemFixedPermissions, context);
- // Revoke appops
List<AppOp> appOpsToRevoke = new ArrayList<>(mAppOps);
- size = remainingRolesHeld.size();
- for (int i = 0; i < size; i++) {
- appOpsToRevoke.removeAll(roles.get(remainingRolesHeld.get(i)).getAppOps());
+ for (int i = 0; i < otherRoleNamesSize; i++) {
+ String roleName = otherRoleNames.get(i);
+ Role role = roles.get(roleName);
+ appOpsToRevoke.removeAll(role.getAppOps());
}
int appOpsSize = appOpsToRevoke.size();
for (int i = 0; i < appOpsSize; i++) {
- permissionOrAppOpChanged |= appOpsToRevoke.get(i).revoke(packageName, context);
+ AppOp appOp = appOpsToRevoke.get(i);
+ permissionOrAppOpChanged |= appOp.revoke(packageName, context);
}
// TODO: STOPSHIP: Revoke preferred activities?
@@ -303,7 +345,7 @@ public class Role {
}
}
- private void killApp(@NonNull String packageName, @NonNull Context context) {
+ private static void killApp(@NonNull String packageName, @NonNull Context context) {
ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
if (applicationInfo == null) {
Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName);
@@ -317,7 +359,9 @@ public class Role {
public String toString() {
return "Role{"
+ "mName='" + mName + '\''
+ + ", mAvailabilityProvider=" + mAvailabilityProvider
+ ", mExclusive=" + mExclusive
+ + ", mLabelResource=" + mLabelResource
+ ", mRequiredComponents=" + mRequiredComponents
+ ", mPermissions=" + mPermissions
+ ", mAppOps=" + mAppOps
@@ -335,7 +379,9 @@ public class Role {
}
Role role = (Role) object;
return mExclusive == role.mExclusive
+ && mLabelResource == role.mLabelResource
&& Objects.equals(mName, role.mName)
+ && Objects.equals(mAvailabilityProvider, role.mAvailabilityProvider)
&& Objects.equals(mRequiredComponents, role.mRequiredComponents)
&& Objects.equals(mPermissions, role.mPermissions)
&& Objects.equals(mAppOps, role.mAppOps)
@@ -344,7 +390,7 @@ public class Role {
@Override
public int hashCode() {
- return Objects.hash(mName, mExclusive, mRequiredComponents, mPermissions, mAppOps,
- mPreferredActivities);
+ return Objects.hash(mName, mAvailabilityProvider, mExclusive, mLabelResource,
+ mRequiredComponents, mPermissions, mAppOps, mPreferredActivities);
}
}
diff --git a/src/com/android/packageinstaller/role/model/RoleAvailabilityProvider.java b/src/com/android/packageinstaller/role/model/RoleAvailabilityProvider.java
new file mode 100644
index 00000000..4c7207d5
--- /dev/null
+++ b/src/com/android/packageinstaller/role/model/RoleAvailabilityProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.packageinstaller.role.model;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Interface for determining whether a role is available.
+ */
+public interface RoleAvailabilityProvider {
+
+ /**
+ * Check whether a role is available
+ *
+ * @param user the user to check for
+ * @param context the {@code Context} to retrieve system services
+ *
+ * @return Whether the role is available
+ */
+ boolean isRoleAvailableAsUser(@NonNull UserHandle user, @NonNull Context context);
+}
diff --git a/src/com/android/packageinstaller/role/model/Roles.java b/src/com/android/packageinstaller/role/model/Roles.java
index 8d8afce6..423bd5c2 100644
--- a/src/com/android/packageinstaller/role/model/Roles.java
+++ b/src/com/android/packageinstaller/role/model/Roles.java
@@ -70,9 +70,10 @@ public class Roles {
private static final String TAG_PREFERRED_ACTIVITIES = "preferred-activities";
private static final String TAG_PREFERRED_ACTIVITY = "preferred-activity";
private static final String ATTRIBUTE_NAME = "name";
- private static final String ATTRIBUTE_PERMISSION = "permission";
+ private static final String ATTRIBUTE_AVAILABILITY_PROVIDER = "availabilityProvider";
private static final String ATTRIBUTE_EXCLUSIVE = "exclusive";
private static final String ATTRIBUTE_LABEL = "label";
+ private static final String ATTRIBUTE_PERMISSION = "permission";
private static final String ATTRIBUTE_SCHEME = "scheme";
private static final String ATTRIBUTE_MIME_TYPE = "mimeType";
private static final String ATTRIBUTE_VALUE = "value";
@@ -290,6 +291,25 @@ public class Roles {
return null;
}
+ String availabilityProviderClassSimpleName = getAttributeValue(parser,
+ ATTRIBUTE_AVAILABILITY_PROVIDER);
+ RoleAvailabilityProvider availabilityProvider;
+ if (availabilityProviderClassSimpleName != null) {
+ String availabilityProviderClassName = Roles.class.getPackage().getName() + '.'
+ + availabilityProviderClassSimpleName;
+ try {
+ availabilityProvider = (RoleAvailabilityProvider) Class.forName(
+ availabilityProviderClassName).newInstance();
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
+ throwOrLogMessage("Unable to instantiate availability provider: "
+ + availabilityProviderClassName, e);
+ skipCurrentTag(parser);
+ return null;
+ }
+ } else {
+ availabilityProvider = null;
+ }
+
Boolean exclusive = requireAttributeBooleanValue(parser, ATTRIBUTE_EXCLUSIVE, true,
TAG_ROLE);
if (exclusive == null) {
@@ -363,8 +383,8 @@ public class Roles {
if (preferredActivities == null) {
preferredActivities = Collections.emptyList();
}
- return new Role(name, labelResource, exclusive, requiredComponents, permissions, appOps,
- preferredActivities);
+ return new Role(name, availabilityProvider, exclusive, labelResource, requiredComponents,
+ permissions, appOps, preferredActivities);
}
@NonNull
diff --git a/src/com/android/packageinstaller/role/model/SmsRoleAvailabilityProvider.java b/src/com/android/packageinstaller/role/model/SmsRoleAvailabilityProvider.java
new file mode 100644
index 00000000..d4d82427
--- /dev/null
+++ b/src/com/android/packageinstaller/role/model/SmsRoleAvailabilityProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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.packageinstaller.role.model;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telephony.TelephonyManager;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Class for determining whether the SMS role is available.
+ *
+ * @see com.android.settings.applications.DefaultAppSettings
+ * @see com.android.settings.applications.defaultapps.DefaultSmsPreferenceController#isAvailable()
+ */
+public class SmsRoleAvailabilityProvider implements RoleAvailabilityProvider {
+
+ @Override
+ public boolean isRoleAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) {
+ UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager.isManagedProfile(user.getIdentifier())) {
+ return false;
+ }
+ // FIXME: STOPSHIP: Add an appropriate @SystemApi for this.
+ //if (userManager.getUserInfo(user.getIdentifier()).isRestricted()) {
+ // return false;
+ //}
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ if (!telephonyManager.isSmsCapable()) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java b/src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java
index f96b24ae..37049b60 100644
--- a/src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java
+++ b/src/com/android/packageinstaller/role/service/RoleControllerServiceImpl.java
@@ -128,10 +128,20 @@ public class RoleControllerServiceImpl extends RoleControllerService {
Log.e(LOG_TAG, "callback cannot be null");
return;
}
+
ArrayMap<String, Role> roles = Roles.getRoles(this);
+ List<String> roleNames = new ArrayList<>();
+ int rolesSize = roles.size();
+ for (int i = 0; i < rolesSize; i++) {
+ Role role = roles.valueAt(i);
+ if (!role.isAvailable(this)) {
+ continue;
+ }
+ roleNames.add(role.getName());
+ }
// TODO: Clean up holders of roles that will be removed.
- List<String> roleNames = new ArrayList<>(roles.keySet());
mRoleManager.setRoleNamesFromController(roleNames);
+
//TODO grant default permissions and appops
Log.i(LOG_TAG, "Granting defaults for user " + UserHandle.myUserId());
callback.onSuccess();
@@ -146,6 +156,11 @@ public class RoleControllerServiceImpl extends RoleControllerService {
callback.onFailure();
return;
}
+ if (!role.isAvailable(this)) {
+ Log.e(LOG_TAG, "Role is unavailable: " + roleName);
+ callback.onFailure();
+ return;
+ }
ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, this);
if (applicationInfo == null) {
@@ -207,6 +222,11 @@ public class RoleControllerServiceImpl extends RoleControllerService {
callback.onFailure();
return;
}
+ if (!role.isAvailable(this)) {
+ Log.e(LOG_TAG, "Role is unavailable: " + roleName);
+ callback.onFailure();
+ return;
+ }
boolean removed = removeRoleHolderInternal(role, packageName);
if (!removed) {
@@ -227,6 +247,11 @@ public class RoleControllerServiceImpl extends RoleControllerService {
callback.onFailure();
return;
}
+ if (!role.isAvailable(this)) {
+ Log.e(LOG_TAG, "Role is unavailable: " + roleName);
+ callback.onFailure();
+ return;
+ }
List<String> packageNames = mRoleManager.getRoleHolders(roleName);
int packageNamesSize = packageNames.size();
diff --git a/src/com/android/packageinstaller/role/ui/DefaultAppActivity.java b/src/com/android/packageinstaller/role/ui/DefaultAppActivity.java
index 67b2dc9b..1b5e94fa 100644
--- a/src/com/android/packageinstaller/role/ui/DefaultAppActivity.java
+++ b/src/com/android/packageinstaller/role/ui/DefaultAppActivity.java
@@ -67,6 +67,11 @@ public class DefaultAppActivity extends FragmentActivity {
finish();
return;
}
+ if (!role.isAvailableAsUser(user, this)) {
+ Log.e(LOG_TAG, "Role is unavailable: " + roleName);
+ finish();
+ return;
+ }
if (savedInstanceState == null) {
DefaultAppFragment fragment = DefaultAppFragment.newInstance(roleName, user);
diff --git a/src/com/android/packageinstaller/role/ui/RequestRoleActivity.java b/src/com/android/packageinstaller/role/ui/RequestRoleActivity.java
index 591d220f..0c541730 100644
--- a/src/com/android/packageinstaller/role/ui/RequestRoleActivity.java
+++ b/src/com/android/packageinstaller/role/ui/RequestRoleActivity.java
@@ -77,6 +77,12 @@ public class RequestRoleActivity extends FragmentActivity {
return;
}
+ if (!role.isAvailable(this)) {
+ Log.e(LOG_TAG, "Role is unavailable: " + mRoleName);
+ finish();
+ return;
+ }
+
if (PackageUtils.getApplicationInfo(mPackageName, this) == null) {
Log.w(LOG_TAG, "Unknown application: " + mPackageName);
finish();
diff --git a/src/com/android/packageinstaller/role/ui/RoleListLiveData.java b/src/com/android/packageinstaller/role/ui/RoleListLiveData.java
index c4435a77..3a5b617b 100644
--- a/src/com/android/packageinstaller/role/ui/RoleListLiveData.java
+++ b/src/com/android/packageinstaller/role/ui/RoleListLiveData.java
@@ -91,6 +91,10 @@ public class RoleListLiveData extends AsyncTaskLiveData<List<RoleItem>>
continue;
}
+ if (!role.isAvailableAsUser(mUser, mContext)) {
+ continue;
+ }
+
if (role.getQualifyingPackagesAsUser(mUser, mContext).isEmpty()) {
continue;
}