summaryrefslogtreecommitdiffstats
path: root/src/org/cyanogenmod/themes/provider/util/IconPreviewHelper.java
blob: 484136c47bc281dd3689d3bd44a1f8e43c89130c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
 * Copyright (C) 2014 The CyanogenMod 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 org.cyanogenmod.themes.provider.util;

import android.app.ActivityManager;
import android.app.ComposedIconInfo;
import android.app.IconPackHelper;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;

/**
 * This class handles all the logic to build a preview icon
 * If the system currently has a theme applied we do NOT
 * want this code to be impacted by it. So code in this
 * class creates special "no theme attached" resource objects
 * to retrieve objects from.
 */
public class IconPreviewHelper {
    private static final String TAG = IconPreviewHelper.class.getSimpleName();
    private final static float ICON_SCALE_FACTOR = 1.3f; //Arbitrary. Looks good

    private Context mContext;
    private DisplayMetrics mDisplayMetrics;
    private Configuration mConfiguration;
    private int mIconDpi = 0;
    private String mThemePkgName;
    private IconPackHelper mIconPackHelper;
    private int mIconSize;

    /**
     * @param themePkgName - The package name of the theme we wish to preview
     */
    public IconPreviewHelper(Context context, String themePkgName) {
        mContext = context;
        mDisplayMetrics = context.getResources().getDisplayMetrics();
        mConfiguration = context.getResources().getConfiguration();
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        mIconDpi = (int) (am.getLauncherLargeIconDensity() * ICON_SCALE_FACTOR);
        mThemePkgName = themePkgName;
        mIconPackHelper = new IconPackHelper(mContext);
        try {
            mIconPackHelper.loadIconPack(mThemePkgName);
        } catch (NameNotFoundException e) {}
        mIconSize = (int) (am.getLauncherLargeIconSize() * ICON_SCALE_FACTOR);
    }

    /**
     * Returns the actual label name for a given component
     * If the activity does not have a label it will return app's label
     * If neither has a label returns empty string
     */
    public String getLabel(ComponentName component) {
        String label = "";
        try {
            PackageManager pm = mContext.getPackageManager();
            ApplicationInfo appInfo = pm.getApplicationInfo(component.getPackageName(), 0);
            ActivityInfo activityInfo = pm.getActivityInfo(component, 0);

            AssetManager assets = new AssetManager();
            assets.addAssetPath(appInfo.publicSourceDir);
            Resources res = new Resources(assets, mDisplayMetrics, mConfiguration);

            if (activityInfo.labelRes != 0) {
                label = res.getString(activityInfo.labelRes);
            } else if (appInfo.labelRes != 0) {
                label = res.getString(appInfo.labelRes);
            }
        } catch(NameNotFoundException exception) {
            Log.e(TAG, "unable to find pkg for " + component.toString());
        }
        return label;
    }

    /**
     * Returns the icon for the given component regardless of the system's
     * currently applied theme. If the preview theme does not support the icon, then
     * return the system default icon.
     */
    public Drawable getIcon(ComponentName component) {
        String packageName = component.getPackageName();
        String activityName = component.getClassName();
        Drawable icon = getThemedIcon(packageName, activityName);
        if (icon == null) {
            icon = getDefaultIcon(packageName, activityName);
        }
        if (icon != null) {
            icon.setBounds(0, 0, mIconSize, mIconSize);
        }
        return icon;
    }

    private Drawable getThemedIcon(String pkgName, String activityName) {
        Drawable drawable = null;
        ActivityInfo info = new ActivityInfo();
        info.packageName = pkgName;
        info.name = activityName;
        drawable = mIconPackHelper.getDrawableForActivityWithDensity(info, mIconDpi);

        return drawable;
    }

    /**
     * Returns the default icon.  This can be the normal icon associated with the app or a composed
     * icon if the icon pack supports background, mask, and/or foreground.
     * @param pkgName
     * @param activityName
     * @return
     */
    private Drawable getDefaultIcon(String pkgName, String activityName) {
        Drawable drawable = null;
        ComponentName component = new ComponentName(pkgName, activityName);
        PackageManager pm = mContext.getPackageManager();
        Resources res = null;
        try {
            ActivityInfo info = pm.getActivityInfo(component, 0);
            ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);

            res = pm.getThemedResourcesForApplication(pkgName, mThemePkgName);

            final int iconId = info.icon != 0 ? info.icon : appInfo.icon;
            info.themedIcon = 0;
            setupComposedIcon(res, info, iconId);
            drawable = getFullResIcon(res, iconId);
        } catch (NameNotFoundException e2) {
           Log.w(TAG, "Unable to get the icon for " + pkgName + " using default");
        }
        drawable = (drawable != null) ?
                getComposedIcon(res, drawable) : getFullResDefaultActivityIcon();
        return drawable;
    }

    private Drawable getComposedIcon(Resources res, Drawable baseIcon) {
        ComposedIconInfo iconInfo = mIconPackHelper.getComposedIconInfo();
        if (res != null && iconInfo != null && (iconInfo.iconBacks != null ||
                iconInfo.iconMask != 0 || iconInfo.iconUpon != 0)) {
            return IconPackHelper.IconCustomizer.getComposedIconDrawable(baseIcon, res, iconInfo);
        }
        return baseIcon;
    }

    private void setupComposedIcon(Resources res, ActivityInfo info, int iconId) {
        ComposedIconInfo iconInfo = mIconPackHelper.getComposedIconInfo();

        res.setComposedIconInfo(iconInfo);

        SparseArray<PackageItemInfo> icons = new SparseArray<PackageItemInfo>(1);
        info.themedIcon = 0;
        icons.put(iconId, info);
        res.setIconResources(icons);
    }

    private Drawable getFullResIcon(Resources resources, int iconId) {
        Drawable d;
        try {
            d = resources.getDrawableForDensity(iconId, mIconDpi, null, false);
        } catch (Resources.NotFoundException e) {
            d = null;
        }
        return (d != null) ? d : getFullResDefaultActivityIcon();
    }

    private Drawable getFullResDefaultActivityIcon() {
        return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
    }
}