blob: 487558f81e4518ade57765bfb848032d3b0692cc [file] [log] [blame]
/*
* Copyright (C) 2016 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.server.pm;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.util.Preconditions;
import libcore.util.Objects;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.function.Consumer;
/**
* User information used by {@link ShortcutService}.
*/
class ShortcutUser {
private static final String TAG = ShortcutService.TAG;
static final String TAG_ROOT = "user";
private static final String TAG_LAUNCHER = "launcher";
private static final String ATTR_VALUE = "value";
static final class PackageWithUser {
final int userId;
final String packageName;
private PackageWithUser(int userId, String packageName) {
this.userId = userId;
this.packageName = Preconditions.checkNotNull(packageName);
}
public static PackageWithUser of(int launcherUserId, String packageName) {
return new PackageWithUser(launcherUserId, packageName);
}
public static PackageWithUser of(ShortcutPackageItem spi) {
return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
}
@Override
public int hashCode() {
return packageName.hashCode() ^ userId;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PackageWithUser)) {
return false;
}
final PackageWithUser that = (PackageWithUser) obj;
return userId == that.userId && packageName.equals(that.packageName);
}
@Override
public String toString() {
return String.format("{Launcher: %d, %s}", userId, packageName);
}
}
@UserIdInt
final int mUserId;
private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
private ComponentName mLauncherComponent;
public ShortcutUser(int userId) {
mUserId = userId;
}
public ArrayMap<String, ShortcutPackage> getPackages() {
return mPackages;
}
public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
return mLaunchers;
}
public void addLauncher(ShortcutLauncher launcher) {
mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
launcher.getPackageName()), launcher);
}
public ShortcutLauncher removeLauncher(
@UserIdInt int packageUserId, @NonNull String packageName) {
return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
}
public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
ShortcutPackage ret = mPackages.get(packageName);
if (ret == null) {
ret = new ShortcutPackage(mUserId, packageName);
mPackages.put(packageName, ret);
}
return ret;
}
public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
@UserIdInt int launcherUserId) {
final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
ShortcutLauncher ret = mLaunchers.get(key);
if (ret == null) {
ret = new ShortcutLauncher(mUserId, packageName, launcherUserId);
mLaunchers.put(key, ret);
}
return ret;
}
public void forAllPackageItems(Consumer<ShortcutPackageItem> callback) {
{
final int size = mLaunchers.size();
for (int i = 0; i < size; i++) {
callback.accept(mLaunchers.valueAt(i));
}
}
{
final int size = mPackages.size();
for (int i = 0; i < size; i++) {
callback.accept(mPackages.valueAt(i));
}
}
}
public void unshadowPackage(ShortcutService s, @NonNull String packageName,
@UserIdInt int packageUserId) {
forPackageItem(packageName, packageUserId, spi -> {
Slog.i(TAG, String.format("Restoring for %s, user=%d", packageName, packageUserId));
spi.ensureNotShadowAndSave(s);
});
}
public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
Consumer<ShortcutPackageItem> callback) {
forAllPackageItems(spi -> {
if ((spi.getPackageUserId() == packageUserId)
&& spi.getPackageName().equals(packageName)) {
callback.accept(spi);
}
});
}
public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException {
out.startTag(null, TAG_ROOT);
ShortcutService.writeTagValue(out, TAG_LAUNCHER,
mLauncherComponent);
// Can't use forEachPackageItem due to the checked exceptions.
{
final int size = mLaunchers.size();
for (int i = 0; i < size; i++) {
saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup);
}
}
{
final int size = mPackages.size();
for (int i = 0; i < size; i++) {
saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup);
}
}
out.endTag(null, TAG_ROOT);
}
private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
if (forBackup) {
if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
return; // Don't save.
}
if (spi.getPackageUserId() != spi.getOwnerUserId()) {
return; // Don't save cross-user information.
}
}
spi.saveToXml(out, forBackup);
}
public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
boolean fromBackup) throws IOException, XmlPullParserException {
final ShortcutUser ret = new ShortcutUser(userId);
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final int depth = parser.getDepth();
final String tag = parser.getName();
if (depth == outerDepth + 1) {
switch (tag) {
case TAG_LAUNCHER: {
ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
parser, ATTR_VALUE);
continue;
}
case ShortcutPackage.TAG_ROOT: {
final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
s, parser, userId, fromBackup);
// Don't use addShortcut(), we don't need to save the icon.
ret.getPackages().put(shortcuts.getPackageName(), shortcuts);
continue;
}
case ShortcutLauncher.TAG_ROOT: {
ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId, fromBackup));
continue;
}
}
}
ShortcutService.warnForInvalidTag(depth, tag);
}
return ret;
}
public ComponentName getLauncherComponent() {
return mLauncherComponent;
}
public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) {
if (Objects.equal(mLauncherComponent, launcherComponent)) {
return;
}
mLauncherComponent = launcherComponent;
s.scheduleSaveUser(mUserId);
}
public void resetThrottling() {
for (int i = mPackages.size() - 1; i >= 0; i--) {
mPackages.valueAt(i).resetThrottling();
}
}
public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
pw.print(prefix);
pw.print("User: ");
pw.print(mUserId);
pw.println();
pw.print(prefix);
pw.print(" ");
pw.print("Default launcher: ");
pw.print(mLauncherComponent);
pw.println();
for (int i = 0; i < mLaunchers.size(); i++) {
mLaunchers.valueAt(i).dump(s, pw, prefix + " ");
}
for (int i = 0; i < mPackages.size(); i++) {
mPackages.valueAt(i).dump(s, pw, prefix + " ");
}
}
}