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.custom;
17 
18 import static com.android.customization.model.ResourceConstants.ANDROID_PACKAGE;
19 import static com.android.customization.model.ResourceConstants.ICONS_FOR_PREVIEW;
20 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_ANDROID;
21 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_LAUNCHER;
22 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SETTINGS;
23 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_SYSUI;
24 import static com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_ICON_THEMEPICKER;
25 
26 import android.content.Context;
27 import android.content.pm.PackageManager.NameNotFoundException;
28 import android.content.res.Resources;
29 import android.content.res.Resources.NotFoundException;
30 import android.graphics.drawable.Drawable;
31 import android.os.UserHandle;
32 import android.util.Log;
33 
34 import com.android.customization.model.ResourceConstants;
35 import com.android.customization.model.theme.OverlayManagerCompat;
36 import com.android.customization.model.theme.custom.ThemeComponentOption.IconOption;
37 import com.android.wallpaper.R;
38 
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 
44 /**
45  * Implementation of {@link ThemeComponentOptionProvider} that reads {@link IconOption}s from
46  * icon overlays.
47  */
48 public class IconOptionsProvider extends ThemeComponentOptionProvider<IconOption> {
49 
50     private static final String TAG = "IconOptionsProvider";
51 
52     private final List<String> mSysUiIconsOverlayPackages = new ArrayList<>();
53     private final List<String> mSettingsIconsOverlayPackages = new ArrayList<>();
54     private final List<String> mLauncherIconsOverlayPackages = new ArrayList<>();
55     private final List<String> mThemePickerIconsOverlayPackages = new ArrayList<>();
56 
IconOptionsProvider(Context context, OverlayManagerCompat manager)57     public IconOptionsProvider(Context context, OverlayManagerCompat manager) {
58         super(context, manager, OVERLAY_CATEGORY_ICON_ANDROID);
59         String[] targetPackages = ResourceConstants.getPackagesToOverlay(context);
60         mSysUiIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory(
61                 OVERLAY_CATEGORY_ICON_SYSUI, UserHandle.myUserId(), targetPackages));
62         mSettingsIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory(
63                 OVERLAY_CATEGORY_ICON_SETTINGS, UserHandle.myUserId(), targetPackages));
64         mLauncherIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory(
65                 OVERLAY_CATEGORY_ICON_LAUNCHER, UserHandle.myUserId(), targetPackages));
66         mThemePickerIconsOverlayPackages.addAll(manager.getOverlayPackagesForCategory(
67                 OVERLAY_CATEGORY_ICON_THEMEPICKER, UserHandle.myUserId(), targetPackages));
68     }
69 
70     @Override
loadOptions()71     protected void loadOptions() {
72         addDefault();
73 
74         Map<String, IconOption> optionsByPrefix = new HashMap<>();
75         for (String overlayPackage : mOverlayPackages) {
76             IconOption option = addOrUpdateOption(optionsByPrefix, overlayPackage,
77                     OVERLAY_CATEGORY_ICON_ANDROID);
78             try{
79                 for (String iconName : ICONS_FOR_PREVIEW) {
80                     option.addIcon(loadIconPreviewDrawable(iconName, overlayPackage));
81                 }
82             } catch (NotFoundException | NameNotFoundException e) {
83                 Log.w(TAG, String.format("Couldn't load icon overlay details for %s, will skip it",
84                         overlayPackage), e);
85             }
86         }
87 
88         for (String overlayPackage : mSysUiIconsOverlayPackages) {
89             addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_SYSUI);
90         }
91 
92         for (String overlayPackage : mSettingsIconsOverlayPackages) {
93             addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_SETTINGS);
94         }
95 
96         for (String overlayPackage : mLauncherIconsOverlayPackages) {
97             addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_LAUNCHER);
98         }
99 
100         for (String overlayPackage : mThemePickerIconsOverlayPackages) {
101             addOrUpdateOption(optionsByPrefix, overlayPackage, OVERLAY_CATEGORY_ICON_THEMEPICKER);
102         }
103 
104         for (IconOption option : optionsByPrefix.values()) {
105             if (option.isValid(mContext)) {
106                 mOptions.add(option);
107                 option.setLabel(mContext.getString(R.string.icon_component_label, mOptions.size()));
108             }
109         }
110     }
111 
addOrUpdateOption(Map<String, IconOption> optionsByPrefix, String overlayPackage, String category)112     private IconOption addOrUpdateOption(Map<String, IconOption> optionsByPrefix,
113             String overlayPackage, String category) {
114         String prefix = overlayPackage.substring(0, overlayPackage.lastIndexOf("."));
115         IconOption option;
116         if (!optionsByPrefix.containsKey(prefix)) {
117             option = new IconOption();
118             optionsByPrefix.put(prefix, option);
119         } else {
120             option = optionsByPrefix.get(prefix);
121         }
122         option.addOverlayPackage(category, overlayPackage);
123         return option;
124     }
125 
loadIconPreviewDrawable(String drawableName, String packageName)126     private Drawable loadIconPreviewDrawable(String drawableName, String packageName)
127             throws NameNotFoundException, NotFoundException {
128         final Resources resources = ANDROID_PACKAGE.equals(packageName)
129                 ? Resources.getSystem()
130                 : mContext.getPackageManager().getResourcesForApplication(packageName);
131         return resources.getDrawable(
132                 resources.getIdentifier(drawableName, "drawable", packageName), null);
133     }
134 
addDefault()135     private void addDefault() {
136         IconOption option = new IconOption();
137         option.setLabel(mContext.getString(R.string.default_theme_title));
138         try {
139             for (String iconName : ICONS_FOR_PREVIEW) {
140                 option.addIcon(loadIconPreviewDrawable(iconName, ANDROID_PACKAGE));
141             }
142         } catch (NameNotFoundException | NotFoundException e) {
143             Log.w(TAG, "Didn't find SystemUi package icons, will skip option", e);
144         }
145         option.addOverlayPackage(OVERLAY_CATEGORY_ICON_ANDROID, null);
146         option.addOverlayPackage(OVERLAY_CATEGORY_ICON_SYSUI, null);
147         option.addOverlayPackage(OVERLAY_CATEGORY_ICON_SETTINGS, null);
148         option.addOverlayPackage(OVERLAY_CATEGORY_ICON_LAUNCHER, null);
149         option.addOverlayPackage(OVERLAY_CATEGORY_ICON_THEMEPICKER, null);
150         mOptions.add(option);
151     }
152 
153 }
154