1package com.android.launcher3;
2
3import android.annotation.TargetApi;
4import android.appwidget.AppWidgetHostView;
5import android.appwidget.AppWidgetProviderInfo;
6import android.content.ComponentName;
7import android.content.Context;
8import android.content.pm.PackageManager;
9import android.graphics.Point;
10import android.graphics.Rect;
11import android.graphics.drawable.Drawable;
12import android.os.Build;
13import android.os.Parcel;
14
15/**
16 * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
17 * a common object for describing both framework provided AppWidgets as well as custom widgets
18 * (who's implementation is owned by the launcher). This object represents a widget type / class,
19 * as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo}
20 */
21public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
22
23    public boolean isCustomWidget = false;
24
25    public int spanX;
26    public int spanY;
27    public int minSpanX;
28    public int minSpanY;
29
30    public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context,
31            AppWidgetProviderInfo info) {
32
33        // In lieu of a public super copy constructor, we first write the AppWidgetProviderInfo
34        // into a parcel, and then construct a new LauncherAppWidgetProvider info from the
35        // associated super parcel constructor. This allows us to copy non-public members without
36        // using reflection.
37        Parcel p = Parcel.obtain();
38        info.writeToParcel(p, 0);
39        p.setDataPosition(0);
40        LauncherAppWidgetProviderInfo lawpi = new LauncherAppWidgetProviderInfo(p);
41        p.recycle();
42        return lawpi;
43    }
44
45    public LauncherAppWidgetProviderInfo(Parcel in) {
46        super(in);
47        initSpans();
48    }
49
50    public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) {
51        isCustomWidget = true;
52
53        provider = new ComponentName(context, widget.getClass().getName());
54        icon = widget.getIcon();
55        label = widget.getLabel();
56        previewImage = widget.getPreviewImage();
57        initialLayout = widget.getWidgetLayout();
58        resizeMode = widget.getResizeMode();
59        initSpans();
60    }
61
62    private void initSpans() {
63        LauncherAppState app = LauncherAppState.getInstance();
64        InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
65
66        // We only care out the cell size, which is independent of the the layout direction.
67        Rect paddingLand = idp.landscapeProfile.getWorkspacePadding(false /* isLayoutRtl */);
68        Rect paddingPort = idp.portraitProfile.getWorkspacePadding(false /* isLayoutRtl */);
69
70        // Always assume we're working with the smallest span to make sure we
71        // reserve enough space in both orientations.
72        float smallestCellWidth = DeviceProfile.calculateCellWidth(Math.min(
73                idp.landscapeProfile.widthPx - paddingLand.left - paddingLand.right,
74                idp.portraitProfile.widthPx - paddingPort.left - paddingPort.right),
75                idp.numColumns);
76        float smallestCellHeight = DeviceProfile.calculateCellWidth(Math.min(
77                idp.landscapeProfile.heightPx - paddingLand.top - paddingLand.bottom,
78                idp.portraitProfile.heightPx - paddingPort.top - paddingPort.bottom),
79                idp.numRows);
80
81        // We want to account for the extra amount of padding that we are adding to the widget
82        // to ensure that it gets the full amount of space that it has requested.
83        Rect widgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(
84                app.getContext(), provider, null);
85        spanX = Math.max(1, (int) Math.ceil(
86                        (minWidth + widgetPadding.left + widgetPadding.right) / smallestCellWidth));
87        spanY = Math.max(1, (int) Math.ceil(
88                (minHeight + widgetPadding.top + widgetPadding.bottom) / smallestCellHeight));
89
90        minSpanX = Math.max(1, (int) Math.ceil(
91                (minResizeWidth + widgetPadding.left + widgetPadding.right) / smallestCellWidth));
92        minSpanY = Math.max(1, (int) Math.ceil(
93                (minResizeHeight + widgetPadding.top + widgetPadding.bottom) / smallestCellHeight));
94    }
95
96    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
97    public String getLabel(PackageManager packageManager) {
98        if (isCustomWidget) {
99            return Utilities.trim(label);
100        }
101        return super.loadLabel(packageManager);
102    }
103
104    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
105    public Drawable getIcon(Context context, IconCache cache) {
106        if (isCustomWidget) {
107            return cache.getFullResIcon(provider.getPackageName(), icon);
108        }
109        return super.loadIcon(context,
110                LauncherAppState.getInstance().getInvariantDeviceProfile().fillResIconDpi);
111    }
112
113    public String toString(PackageManager pm) {
114        if (isCustomWidget) {
115            return "WidgetProviderInfo(" + provider + ")";
116        }
117        return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s",
118                provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm));
119    }
120
121    public Point getMinSpans(InvariantDeviceProfile idp, Context context) {
122        return new Point(
123                (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1,
124                        (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1);
125    }
126 }
127