Nicolas Prevot | 5f22bf5 | 2014-07-24 19:30:55 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014, The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 17 | package com.android.managedprovisioning.task; |
| 18 | |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 19 | import android.content.BroadcastReceiver; |
Nicolas Prevot | c319f8d | 2014-08-19 12:02:13 +0100 | [diff] [blame] | 20 | import android.content.ComponentName; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 21 | import android.content.Context; |
| 22 | import android.content.Intent; |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 23 | import android.content.pm.ApplicationInfo; |
Nicolas Prevot | b20503c | 2014-08-26 17:05:33 +0100 | [diff] [blame] | 24 | import android.content.pm.ComponentInfo; |
Adam Connors | 012c9bb | 2014-07-14 08:59:16 +0000 | [diff] [blame] | 25 | import android.content.pm.IPackageDeleteObserver; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 26 | import android.content.pm.IPackageManager; |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 27 | import android.content.pm.PackageManager.NameNotFoundException; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 28 | import android.content.pm.PackageManager; |
| 29 | import android.content.pm.ResolveInfo; |
| 30 | import android.os.RemoteException; |
| 31 | import android.os.ServiceManager; |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 32 | import android.util.Xml; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 33 | |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 34 | import com.android.internal.util.FastXmlSerializer; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 35 | import com.android.managedprovisioning.ProvisionLogger; |
| 36 | import com.android.managedprovisioning.R; |
| 37 | |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 38 | import java.io.File; |
| 39 | import java.io.FileInputStream; |
| 40 | import java.io.FileOutputStream; |
| 41 | import java.io.IOException; |
| 42 | |
Nicolas Prevot | b20503c | 2014-08-26 17:05:33 +0100 | [diff] [blame] | 43 | import java.util.ArrayList; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 44 | import java.util.Arrays; |
| 45 | import java.util.HashSet; |
| 46 | import java.util.List; |
| 47 | import java.util.Set; |
Adam Connors | 012c9bb | 2014-07-14 08:59:16 +0000 | [diff] [blame] | 48 | import java.util.concurrent.atomic.AtomicInteger; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 49 | |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 50 | import org.xmlpull.v1.XmlPullParser; |
| 51 | import org.xmlpull.v1.XmlPullParserException; |
| 52 | import org.xmlpull.v1.XmlSerializer; |
| 53 | |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 54 | /** |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 55 | * Removes all system apps with a launcher that are not required. |
Benjamin Franz | 17f2407 | 2014-10-15 17:51:38 +0100 | [diff] [blame] | 56 | * Also disables sharing via Bluetooth, and components that listen to |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 57 | * ACTION_INSTALL_SHORTCUT. |
| 58 | * This class is called a first time when a user is created, but also after a system update. |
| 59 | * In this case, it checks if the system apps that have been added need to be disabled. |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 60 | */ |
| 61 | public class DeleteNonRequiredAppsTask { |
Sander Alewijnse | 28bffd6 | 2014-06-05 10:54:26 +0100 | [diff] [blame] | 62 | private final Callback mCallback; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 63 | private final Context mContext; |
| 64 | private final IPackageManager mIpm; |
| 65 | private final String mMdmPackageName; |
| 66 | private final PackageManager mPm; |
| 67 | private final int mReqAppsList; |
| 68 | private final int mVendorReqAppsList; |
| 69 | private final int mUserId; |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 70 | private final boolean mNewProfile; // If we are provisioning a new managed profile/device. |
Sander Alewijnse | c629b42 | 2014-11-21 11:29:53 +0000 | [diff] [blame] | 71 | private final boolean mDisableInstallShortcutListenersAndTelecom; |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 72 | |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 73 | private static final String TAG_SYSTEM_APPS = "system-apps"; |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 74 | private static final String TAG_PACKAGE_LIST_ITEM = "item"; |
| 75 | private static final String ATTR_VALUE = "value"; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 76 | |
| 77 | public DeleteNonRequiredAppsTask(Context context, String mdmPackageName, int userId, |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 78 | int requiredAppsList, int vendorRequiredAppsList, boolean newProfile, |
Sander Alewijnse | c629b42 | 2014-11-21 11:29:53 +0000 | [diff] [blame] | 79 | boolean disableInstallShortcutListenersAndTelecom, Callback callback) { |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 80 | mCallback = callback; |
| 81 | mContext = context; |
| 82 | mMdmPackageName = mdmPackageName; |
| 83 | mUserId = userId; |
| 84 | mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); |
| 85 | mPm = context.getPackageManager(); |
| 86 | mReqAppsList = requiredAppsList; |
| 87 | mVendorReqAppsList = vendorRequiredAppsList; |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 88 | mNewProfile = newProfile; |
Sander Alewijnse | c629b42 | 2014-11-21 11:29:53 +0000 | [diff] [blame] | 89 | mDisableInstallShortcutListenersAndTelecom = disableInstallShortcutListenersAndTelecom; |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | public void run() { |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 93 | if (mNewProfile) { |
Benjamin Franz | 17f2407 | 2014-10-15 17:51:38 +0100 | [diff] [blame] | 94 | disableBluetoothSharing(); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 95 | } |
| 96 | deleteNonRequiredApps(); |
| 97 | } |
Nicolas Prevot | b20503c | 2014-08-26 17:05:33 +0100 | [diff] [blame] | 98 | |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 99 | /** |
| 100 | * Returns if this task should be run on OTA. |
| 101 | * This is indicated by the presence of the system apps file. |
| 102 | */ |
| 103 | public static boolean shouldDeleteNonRequiredApps(Context context, int userId) { |
| 104 | return getSystemAppsFile(context, userId).exists(); |
| 105 | } |
| 106 | |
Benjamin Franz | 17f2407 | 2014-10-15 17:51:38 +0100 | [diff] [blame] | 107 | private void disableBluetoothSharing() { |
| 108 | ProvisionLogger.logd("Disabling Bluetooth sharing."); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 109 | disableComponent(new ComponentName("com.android.bluetooth", |
Nicolas Prevot | b20503c | 2014-08-26 17:05:33 +0100 | [diff] [blame] | 110 | "com.android.bluetooth.opp.BluetoothOppLauncherActivity")); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 111 | } |
Nicolas Prevot | b20503c | 2014-08-26 17:05:33 +0100 | [diff] [blame] | 112 | |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 113 | private void deleteNonRequiredApps() { |
Nicolas Prevot | c319f8d | 2014-08-19 12:02:13 +0100 | [diff] [blame] | 114 | ProvisionLogger.logd("Deleting non required apps."); |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 115 | |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 116 | File systemAppsFile = getSystemAppsFile(mContext, mUserId); |
| 117 | systemAppsFile.getParentFile().mkdirs(); // Creating the folder if it does not exist |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 118 | |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 119 | Set<String> currentApps = getCurrentSystemApps(); |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 120 | Set<String> previousApps; |
| 121 | if (mNewProfile) { |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 122 | // Provisioning case. |
| 123 | |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 124 | // If this userId was a managed profile before, file may exist. In this case, we ignore |
| 125 | // what is in this file. |
| 126 | previousApps = new HashSet<String>(); |
| 127 | } else { |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 128 | // OTA case. |
| 129 | |
| 130 | if (!systemAppsFile.exists()) { |
| 131 | // Error, this task should not have been run. |
| 132 | ProvisionLogger.loge("No system apps list found for user " + mUserId); |
| 133 | mCallback.onError(); |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 134 | return; |
| 135 | } |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 136 | |
| 137 | previousApps = readSystemApps(systemAppsFile); |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 138 | } |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 139 | writeSystemApps(currentApps, systemAppsFile); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 140 | Set<String> newApps = currentApps; |
| 141 | newApps.removeAll(previousApps); |
| 142 | |
Sander Alewijnse | c629b42 | 2014-11-21 11:29:53 +0000 | [diff] [blame] | 143 | if (mDisableInstallShortcutListenersAndTelecom) { |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 144 | Intent actionShortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT"); |
| 145 | if (previousApps.isEmpty()) { |
| 146 | // Here, all the apps are in newApps. |
| 147 | // It is faster to do it this way than to go through all the apps one by one. |
| 148 | disableReceivers(actionShortcut); |
| 149 | } else { |
| 150 | // Here, all the apps are not in newApps. So we have to go through all the new |
| 151 | // apps one by one. |
| 152 | for (String newApp : newApps) { |
| 153 | actionShortcut.setPackage(newApp); |
| 154 | disableReceivers(actionShortcut); |
| 155 | } |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 156 | } |
| 157 | } |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 158 | Set<String> packagesToDelete = newApps; |
| 159 | packagesToDelete.removeAll(getRequiredApps()); |
| 160 | packagesToDelete.retainAll(getCurrentAppsWithLauncher()); |
Tyler Gunn | 1c897ab | 2014-09-12 11:11:32 -0700 | [diff] [blame] | 161 | // com.android.server.telecom should not handle CALL intents in the managed profile. |
Sander Alewijnse | c629b42 | 2014-11-21 11:29:53 +0000 | [diff] [blame] | 162 | if (mDisableInstallShortcutListenersAndTelecom && mNewProfile) { |
Tyler Gunn | 1c897ab | 2014-09-12 11:11:32 -0700 | [diff] [blame] | 163 | packagesToDelete.add("com.android.server.telecom"); |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 164 | } |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 165 | if (packagesToDelete.isEmpty()) { |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 166 | mCallback.onSuccess(); |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 167 | return; |
| 168 | } |
| 169 | PackageDeleteObserver packageDeleteObserver = |
| 170 | new PackageDeleteObserver(packagesToDelete.size()); |
| 171 | for (String packageName : packagesToDelete) { |
| 172 | try { |
| 173 | mIpm.deletePackageAsUser(packageName, packageDeleteObserver, mUserId, |
| 174 | PackageManager.DELETE_SYSTEM_APP); |
| 175 | } catch (RemoteException neverThrown) { |
| 176 | // Never thrown, as we are making local calls. |
| 177 | ProvisionLogger.loge("This should not happen.", neverThrown); |
| 178 | } |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 179 | } |
| 180 | } |
| 181 | |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 182 | static File getSystemAppsFile(Context context, int userId) { |
| 183 | return new File(context.getFilesDir() + File.separator + "system_apps" |
| 184 | + File.separator + "user" + userId + ".xml"); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Disable all components that can handle the specified broadcast intent. |
| 189 | */ |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 190 | private void disableReceivers(Intent intent) { |
| 191 | List<ResolveInfo> receivers = mPm.queryBroadcastReceivers(intent, 0, mUserId); |
| 192 | for (ResolveInfo ri : receivers) { |
| 193 | // One of ri.activityInfo, ri.serviceInfo, ri.providerInfo is not null. Let's find which |
| 194 | // one. |
| 195 | ComponentInfo ci; |
| 196 | if (ri.activityInfo != null) { |
| 197 | ci = ri.activityInfo; |
| 198 | } else if (ri.serviceInfo != null) { |
| 199 | ci = ri.serviceInfo; |
| 200 | } else { |
| 201 | ci = ri.providerInfo; |
| 202 | } |
| 203 | disableComponent(new ComponentName(ci.packageName, ci.name)); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | private void disableComponent(ComponentName toDisable) { |
| 208 | try { |
| 209 | mIpm.setComponentEnabledSetting(toDisable, |
| 210 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP, |
| 211 | mUserId); |
| 212 | } catch (RemoteException neverThrown) { |
| 213 | ProvisionLogger.loge("This should not happen.", neverThrown); |
Jessica Hummel | 1bfee7d | 2014-09-25 10:08:40 +0100 | [diff] [blame] | 214 | } catch (Exception e) { |
| 215 | ProvisionLogger.logw("Component not found, not disabling it: " |
| 216 | + toDisable.toShortString()); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 217 | } |
| 218 | } |
| 219 | |
| 220 | /** |
| 221 | * Returns the set of package names of apps that are in the system image, |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 222 | * whether they have been deleted or not. |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 223 | */ |
| 224 | private Set<String> getCurrentSystemApps() { |
| 225 | Set<String> apps = new HashSet<String>(); |
| 226 | List<ApplicationInfo> aInfos = null; |
| 227 | try { |
| 228 | aInfos = mIpm.getInstalledApplications( |
| 229 | PackageManager.GET_UNINSTALLED_PACKAGES, mUserId).getList(); |
| 230 | } catch (RemoteException neverThrown) { |
| 231 | // Never thrown, as we are making local calls. |
| 232 | ProvisionLogger.loge("This should not happen.", neverThrown); |
| 233 | } |
| 234 | for (ApplicationInfo aInfo : aInfos) { |
| 235 | if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { |
| 236 | apps.add(aInfo.packageName); |
| 237 | } |
| 238 | } |
| 239 | return apps; |
| 240 | } |
| 241 | |
| 242 | private Set<String> getCurrentAppsWithLauncher() { |
| 243 | Intent launcherIntent = new Intent(Intent.ACTION_MAIN); |
| 244 | launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER); |
| 245 | List<ResolveInfo> resolveInfos = mPm.queryIntentActivitiesAsUser(launcherIntent, |
Alexandra Gherghina | 5689fcd | 2014-09-09 12:03:18 +0100 | [diff] [blame] | 246 | PackageManager.GET_UNINSTALLED_PACKAGES, mUserId); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 247 | Set<String> apps = new HashSet<String>(); |
| 248 | for (ResolveInfo resolveInfo : resolveInfos) { |
| 249 | apps.add(resolveInfo.activityInfo.packageName); |
| 250 | } |
| 251 | return apps; |
| 252 | } |
| 253 | |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 254 | private void writeSystemApps(Set<String> packageNames, File systemAppsFile) { |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 255 | try { |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 256 | FileOutputStream stream = new FileOutputStream(systemAppsFile, false); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 257 | XmlSerializer serializer = new FastXmlSerializer(); |
| 258 | serializer.setOutput(stream, "utf-8"); |
| 259 | serializer.startDocument(null, true); |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 260 | serializer.startTag(null, TAG_SYSTEM_APPS); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 261 | for (String packageName : packageNames) { |
| 262 | serializer.startTag(null, TAG_PACKAGE_LIST_ITEM); |
| 263 | serializer.attribute(null, ATTR_VALUE, packageName); |
| 264 | serializer.endTag(null, TAG_PACKAGE_LIST_ITEM); |
| 265 | } |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 266 | serializer.endTag(null, TAG_SYSTEM_APPS); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 267 | serializer.endDocument(); |
| 268 | stream.close(); |
| 269 | } catch (IOException e) { |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 270 | ProvisionLogger.loge("IOException trying to write the system apps", e); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 271 | } |
| 272 | } |
| 273 | |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 274 | private Set<String> readSystemApps(File systemAppsFile) { |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 275 | Set<String> result = new HashSet<String>(); |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 276 | if (!systemAppsFile.exists()) { |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 277 | return result; |
| 278 | } |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 279 | try { |
Nicolas Prevot | 7d56b90 | 2014-11-03 15:26:06 +0000 | [diff] [blame] | 280 | FileInputStream stream = new FileInputStream(systemAppsFile); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 281 | |
| 282 | XmlPullParser parser = Xml.newPullParser(); |
| 283 | parser.setInput(stream, null); |
| 284 | |
| 285 | int type = parser.next(); |
| 286 | int outerDepth = parser.getDepth(); |
| 287 | while ((type=parser.next()) != XmlPullParser.END_DOCUMENT |
| 288 | && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| 289 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 290 | continue; |
| 291 | } |
| 292 | String tag = parser.getName(); |
| 293 | if (tag.equals(TAG_PACKAGE_LIST_ITEM)) { |
| 294 | result.add(parser.getAttributeValue(null, ATTR_VALUE)); |
| 295 | } else { |
| 296 | ProvisionLogger.loge("Unknown tag: " + tag); |
| 297 | } |
| 298 | } |
| 299 | stream.close(); |
| 300 | } catch (IOException e) { |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 301 | ProvisionLogger.loge("IOException trying to read the system apps", e); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 302 | } catch (XmlPullParserException e) { |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 303 | ProvisionLogger.loge("XmlPullParserException trying to read the system apps", e); |
Nicolas Prevot | 3b76f0d | 2014-09-03 15:33:42 +0100 | [diff] [blame] | 304 | } |
| 305 | return result; |
| 306 | } |
| 307 | |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 308 | protected Set<String> getRequiredApps() { |
| 309 | HashSet<String> requiredApps = new HashSet<String> (Arrays.asList( |
| 310 | mContext.getResources().getStringArray(mReqAppsList))); |
| 311 | requiredApps.addAll(Arrays.asList( |
| 312 | mContext.getResources().getStringArray(mVendorReqAppsList))); |
| 313 | requiredApps.add(mMdmPackageName); |
| 314 | return requiredApps; |
| 315 | } |
| 316 | |
Adam Connors | 012c9bb | 2014-07-14 08:59:16 +0000 | [diff] [blame] | 317 | /** |
| 318 | * Runs the next task when all packages have been deleted or shuts down the activity if package |
| 319 | * deletion fails. |
| 320 | */ |
| 321 | class PackageDeleteObserver extends IPackageDeleteObserver.Stub { |
| 322 | private final AtomicInteger mPackageCount = new AtomicInteger(0); |
| 323 | |
| 324 | public PackageDeleteObserver(int packageCount) { |
| 325 | this.mPackageCount.set(packageCount); |
| 326 | } |
| 327 | |
| 328 | @Override |
| 329 | public void packageDeleted(String packageName, int returnCode) { |
| 330 | if (returnCode != PackageManager.DELETE_SUCCEEDED) { |
| 331 | ProvisionLogger.logw( |
Nicolas Prevot | 418aaf4 | 2014-09-08 17:51:54 +0100 | [diff] [blame] | 332 | "Could not finish the provisioning: package deletion failed"); |
Adam Connors | 012c9bb | 2014-07-14 08:59:16 +0000 | [diff] [blame] | 333 | mCallback.onError(); |
| 334 | } |
| 335 | int currentPackageCount = mPackageCount.decrementAndGet(); |
| 336 | if (currentPackageCount == 0) { |
| 337 | ProvisionLogger.logi("All non-required system apps have been uninstalled."); |
| 338 | mCallback.onSuccess(); |
| 339 | } |
| 340 | } |
| 341 | } |
| 342 | |
Sander Alewijnse | 2818d32 | 2014-05-20 14:54:13 +0100 | [diff] [blame] | 343 | public abstract static class Callback { |
| 344 | public abstract void onSuccess(); |
| 345 | public abstract void onError(); |
| 346 | } |
| 347 | } |