/* * Copyright (C) 2019 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.customization.model.theme; import android.content.Context; import android.content.om.OverlayInfo; import android.content.om.OverlayManager; import android.os.UserHandle; import androidx.annotation.Nullable; import com.android.customization.model.ResourceConstants; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Wrapper over {@link OverlayManager} that abstracts away its internals and can be mocked for * testing. */ public class OverlayManagerCompat { private final OverlayManager mOverlayManager; private final String[] mTargetPackages; private Map>> mOverlayByUser; public OverlayManagerCompat(Context context) { mOverlayManager = context.getSystemService(OverlayManager.class); mTargetPackages = ResourceConstants.getPackagesToOverlay(context); } public boolean isAvailable() { return mOverlayManager != null; } /** * Enables the overlay provided by the given package for the given user Id * @return true if the operation succeeded */ public boolean setEnabledExclusiveInCategory(String packageName, int userId) { mOverlayManager.setEnabledExclusiveInCategory(packageName, UserHandle.of(userId)); return true; } /** * Disables the overlay provided by the given package for the given user Id * @return true if the operation succeeded */ public boolean disableOverlay(String packageName, int userId) { mOverlayManager.setEnabled(packageName, false, UserHandle.of(userId)); return true; } /** * @return the package name of the currently enabled overlay for the given target package, in * the given category, or {@code null} if none is currently enabled. */ @Nullable public String getEnabledPackageName(String targetPackageName, String category) { // Can't use mOverlayByUser map as the enabled state might change List overlayInfos = getOverlayInfosForTarget(targetPackageName, UserHandle.myUserId()); for (OverlayInfo overlayInfo : overlayInfos) { if (category.equals(overlayInfo.getCategory()) && overlayInfo.isEnabled()) { return overlayInfo.getPackageName(); } } return null; } /** * @return a Map of Category -> PackageName of all the overlays enabled for the given target * packages. It might be empty if no overlay is enabled for those targets. */ public Map getEnabledOverlaysForTargets(String... targetPackages) { Map overlays = new HashMap<>(); for (String target : targetPackages) { addAllEnabledOverlaysForTarget(overlays, target); } return overlays; } public List getOverlayPackagesForCategory(String category, int userId, String... targetPackages) { List overlays = new ArrayList<>(); ensureCategoryMapForUser(userId); for (String target : targetPackages) { for (OverlayInfo info : mOverlayByUser.get(userId).getOrDefault(target, Collections.emptyList())) { if (category.equals(info.getCategory())) { overlays.add(info.getPackageName()); } } } return overlays; } private void ensureCategoryMapForUser(int userId) { if (mOverlayByUser == null) { mOverlayByUser = new HashMap<>(); } if (!mOverlayByUser.containsKey(userId)) { Map> overlaysByTarget = new HashMap<>(); for (String target : mTargetPackages) { overlaysByTarget.put(target, getOverlayInfosForTarget(target, userId)); } mOverlayByUser.put(userId, overlaysByTarget); } } private List getOverlayInfosForTarget(String targetPackageName, int userId) { return mOverlayManager.getOverlayInfosForTarget(targetPackageName, UserHandle.of(userId)); } private void addAllEnabledOverlaysForTarget(Map overlays, String target) { // Can't use mOverlayByUser map as the enabled state might change for (OverlayInfo overlayInfo : getOverlayInfosForTarget(target, UserHandle.myUserId())) { if (overlayInfo.isEnabled()) { overlays.put(overlayInfo.getCategory(), overlayInfo.getPackageName()); } } } }