1 /* 2 * Copyright (C) 2019 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 package com.android.customization.model.theme; 17 18 import android.content.Context; 19 import android.content.om.OverlayInfo; 20 import android.content.om.OverlayManager; 21 import android.os.UserHandle; 22 23 import androidx.annotation.Nullable; 24 25 import com.android.customization.model.ResourceConstants; 26 27 import java.util.ArrayList; 28 import java.util.Collections; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 33 /** 34 * Wrapper over {@link OverlayManager} that abstracts away its internals and can be mocked for 35 * testing. 36 */ 37 public class OverlayManagerCompat { 38 private final OverlayManager mOverlayManager; 39 private final String[] mTargetPackages; 40 private Map<Integer, Map<String, List<OverlayInfo>>> mOverlayByUser; 41 OverlayManagerCompat(Context context)42 public OverlayManagerCompat(Context context) { 43 mOverlayManager = context.getSystemService(OverlayManager.class); 44 mTargetPackages = ResourceConstants.getPackagesToOverlay(context); 45 } 46 isAvailable()47 public boolean isAvailable() { 48 return mOverlayManager != null; 49 } 50 51 /** 52 * Enables the overlay provided by the given package for the given user Id 53 * @return true if the operation succeeded 54 */ setEnabledExclusiveInCategory(String packageName, int userId)55 public boolean setEnabledExclusiveInCategory(String packageName, int userId) { 56 mOverlayManager.setEnabledExclusiveInCategory(packageName, UserHandle.of(userId)); 57 return true; 58 } 59 60 /** 61 * Disables the overlay provided by the given package for the given user Id 62 * @return true if the operation succeeded 63 */ disableOverlay(String packageName, int userId)64 public boolean disableOverlay(String packageName, int userId) { 65 mOverlayManager.setEnabled(packageName, false, UserHandle.of(userId)); 66 return true; 67 } 68 69 /** 70 * @return the package name of the currently enabled overlay for the given target package, in 71 * the given category, or {@code null} if none is currently enabled. 72 */ 73 @Nullable getEnabledPackageName(String targetPackageName, String category)74 public String getEnabledPackageName(String targetPackageName, String category) { 75 // Can't use mOverlayByUser map as the enabled state might change 76 List<OverlayInfo> overlayInfos = getOverlayInfosForTarget(targetPackageName, 77 UserHandle.myUserId()); 78 for (OverlayInfo overlayInfo : overlayInfos) { 79 if (category.equals(overlayInfo.getCategory()) && overlayInfo.isEnabled()) { 80 return overlayInfo.getPackageName(); 81 } 82 } 83 return null; 84 } 85 86 /** 87 * @return a Map of Category -> PackageName of all the overlays enabled for the given target 88 * packages. It might be empty if no overlay is enabled for those targets. 89 */ getEnabledOverlaysForTargets(String... targetPackages)90 public Map<String, String> getEnabledOverlaysForTargets(String... targetPackages) { 91 Map<String, String> overlays = new HashMap<>(); 92 for (String target : targetPackages) { 93 addAllEnabledOverlaysForTarget(overlays, target); 94 } 95 return overlays; 96 } 97 getOverlayPackagesForCategory(String category, int userId, String... targetPackages)98 public List<String> getOverlayPackagesForCategory(String category, int userId, 99 String... targetPackages) { 100 List<String> overlays = new ArrayList<>(); 101 ensureCategoryMapForUser(userId); 102 for (String target : targetPackages) { 103 for (OverlayInfo info 104 : mOverlayByUser.get(userId).getOrDefault(target, Collections.emptyList())) { 105 if (category.equals(info.getCategory())) { 106 overlays.add(info.getPackageName()); 107 } 108 } 109 } 110 return overlays; 111 } 112 ensureCategoryMapForUser(int userId)113 private void ensureCategoryMapForUser(int userId) { 114 if (mOverlayByUser == null) { 115 mOverlayByUser = new HashMap<>(); 116 } 117 if (!mOverlayByUser.containsKey(userId)) { 118 Map<String, List<OverlayInfo>> overlaysByTarget = new HashMap<>(); 119 for (String target : mTargetPackages) { 120 overlaysByTarget.put(target, getOverlayInfosForTarget(target, userId)); 121 } 122 mOverlayByUser.put(userId, overlaysByTarget); 123 } 124 } 125 126 getOverlayInfosForTarget(String targetPackageName, int userId)127 private List<OverlayInfo> getOverlayInfosForTarget(String targetPackageName, int userId) { 128 return mOverlayManager.getOverlayInfosForTarget(targetPackageName, UserHandle.of(userId)); 129 } 130 addAllEnabledOverlaysForTarget(Map<String, String> overlays, String target)131 private void addAllEnabledOverlaysForTarget(Map<String, String> overlays, String target) { 132 // Can't use mOverlayByUser map as the enabled state might change 133 for (OverlayInfo overlayInfo : getOverlayInfosForTarget(target, UserHandle.myUserId())) { 134 if (overlayInfo.isEnabled()) { 135 overlays.put(overlayInfo.getCategory(), overlayInfo.getPackageName()); 136 } 137 } 138 } 139 }