Move to Android N-MR1 SDK.
[android_tools.git] / sdk / sources / android-25 / com / android / server / retaildemo / PreloadAppsInstaller.java
blob2038c9e35f0c3503356e6c92e7c4b79a761cb28e
1 /*
2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.server.retaildemo;
19 import android.app.AppGlobals;
20 import android.app.PackageInstallObserver;
21 import android.content.Context;
22 import android.content.pm.IPackageManager;
23 import android.content.pm.PackageManager;
24 import android.os.Bundle;
25 import android.os.Environment;
26 import android.os.RemoteException;
27 import android.os.UserHandle;
28 import android.provider.Settings;
29 import android.util.ArrayMap;
30 import android.util.Log;
31 import android.util.Slog;
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.util.ArrayUtils;
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.Collections;
39 import java.util.Map;
41 /**
42 * Helper class for installing preloaded APKs
44 class PreloadAppsInstaller {
45 private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
46 private static String TAG = PreloadAppsInstaller.class.getSimpleName();
47 private static final String PRELOAD_APK_EXT = ".apk.preload";
48 private static boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
50 private final IPackageManager mPackageManager;
51 private final File preloadsAppsDirectory;
52 private final Context mContext;
54 private final Map<String, String> mApkToPackageMap;
56 PreloadAppsInstaller(Context context) {
57 this(context, AppGlobals.getPackageManager(), Environment.getDataPreloadsAppsDirectory());
60 @VisibleForTesting
61 PreloadAppsInstaller(Context context, IPackageManager packageManager, File preloadsAppsDirectory) {
62 mContext = context;
63 mPackageManager = packageManager;
64 mApkToPackageMap = Collections.synchronizedMap(new ArrayMap<>());
65 this.preloadsAppsDirectory = preloadsAppsDirectory;
68 void installApps(int userId) {
69 File[] files = preloadsAppsDirectory.listFiles();
70 AppInstallCounter counter = new AppInstallCounter(mContext, userId);
71 if (ArrayUtils.isEmpty(files)) {
72 counter.setExpectedAppsCount(0);
73 return;
75 int expectedCount = 0;
76 for (File file : files) {
77 String apkName = file.getName();
78 if (apkName.endsWith(PRELOAD_APK_EXT) && file.isFile()) {
79 String packageName = mApkToPackageMap.get(apkName);
80 if (packageName != null) {
81 try {
82 expectedCount++;
83 installExistingPackage(packageName, userId, counter);
84 } catch (Exception e) {
85 Slog.e(TAG, "Failed to install existing package " + packageName, e);
87 } else {
88 try {
89 installPackage(file, userId, counter);
90 expectedCount++;
91 } catch (Exception e) {
92 Slog.e(TAG, "Failed to install package from " + file, e);
97 counter.setExpectedAppsCount(expectedCount);
100 private void installExistingPackage(String packageName, int userId,
101 AppInstallCounter counter) {
102 if (DEBUG) {
103 Log.d(TAG, "installExistingPackage " + packageName + " u" + userId);
105 try {
106 mPackageManager.installExistingPackageAsUser(packageName, userId);
107 } catch (RemoteException e) {
108 throw e.rethrowFromSystemServer();
109 } finally {
110 counter.appInstallFinished();
114 private void installPackage(File file, final int userId, AppInstallCounter counter)
115 throws IOException, RemoteException {
116 final String apkName = file.getName();
117 if (DEBUG) {
118 Log.d(TAG, "installPackage " + apkName + " u" + userId);
120 mPackageManager.installPackageAsUser(file.getPath(), new PackageInstallObserver() {
121 @Override
122 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
123 Bundle extras) {
124 if (DEBUG) {
125 Log.d(TAG, "Package " + basePackageName + " installed u" + userId
126 + " returnCode: " + returnCode + " msg: " + msg);
128 // Don't notify the counter for now, we'll do it in installExistingPackage
129 if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
130 mApkToPackageMap.put(apkName, basePackageName);
131 // Install on user 0 so that the package is cached when demo user is re-created
132 installExistingPackage(basePackageName, UserHandle.USER_SYSTEM, counter);
133 } else if (returnCode == PackageManager.INSTALL_FAILED_ALREADY_EXISTS) {
134 // This can only happen in first session after a reboot
135 if (!mApkToPackageMap.containsKey(apkName)) {
136 mApkToPackageMap.put(apkName, basePackageName);
138 installExistingPackage(basePackageName, userId, counter);
139 } else {
140 Log.e(TAG, "Package " + basePackageName + " cannot be installed from "
141 + apkName + ": " + msg + " (returnCode " + returnCode + ")");
142 counter.appInstallFinished();
145 }.getBinder(), 0, SYSTEM_SERVER_PACKAGE_NAME, userId);
148 private static class AppInstallCounter {
149 private int expectedCount = -1; // -1 means expectedCount not set
150 private int finishedCount;
151 private final Context mContext;
152 private final int userId;
154 AppInstallCounter(Context context, int userId) {
155 mContext = context;
156 this.userId = userId;
159 synchronized void appInstallFinished() {
160 this.finishedCount++;
161 checkIfAllFinished();
164 synchronized void setExpectedAppsCount(int expectedCount) {
165 this.expectedCount = expectedCount;
166 checkIfAllFinished();
169 private void checkIfAllFinished() {
170 if (expectedCount == finishedCount) {
171 Log.i(TAG, "All preloads finished installing for user " + userId);
172 Settings.Secure.putStringForUser(mContext.getContentResolver(),
173 Settings.Secure.DEMO_USER_SETUP_COMPLETE, "1", userId);