• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.xtremelabs.robolectric.shadows;
2 
3 import android.app.Activity;
4 import android.app.Application;
5 import android.appwidget.AppWidgetManager;
6 import android.appwidget.AppWidgetProvider;
7 import android.content.ComponentName;
8 import android.content.Context;
9 import android.view.View;
10 import android.widget.RemoteViews;
11 import com.xtremelabs.robolectric.internal.AppSingletonizer;
12 import com.xtremelabs.robolectric.internal.Implementation;
13 import com.xtremelabs.robolectric.internal.Implements;
14 import com.xtremelabs.robolectric.internal.RealObject;
15 
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 
21 import static com.xtremelabs.robolectric.Robolectric.newInstanceOf;
22 import static com.xtremelabs.robolectric.Robolectric.shadowOf;
23 
24 @SuppressWarnings({"UnusedDeclaration"})
25 @Implements(AppWidgetManager.class)
26 public class ShadowAppWidgetManager {
27     private static AppSingletonizer<AppWidgetManager> instances = new AppSingletonizer<AppWidgetManager>(AppWidgetManager.class) {
28         @Override
29         protected AppWidgetManager get(ShadowApplication shadowApplication) {
30             return shadowApplication.appWidgetManager;
31         }
32 
33         @Override
34         protected void set(ShadowApplication shadowApplication, AppWidgetManager instance) {
35             shadowApplication.appWidgetManager = instance;
36         }
37 
38         @Override
39         protected AppWidgetManager createInstance(Application applicationContext) {
40             AppWidgetManager appWidgetManager = super.createInstance(applicationContext);
41             shadowOf(appWidgetManager).context = applicationContext;
42             return appWidgetManager;
43         }
44     };
45 
46     @RealObject
47     private AppWidgetManager realAppWidgetManager;
48 
49     private Context context;
50     private Map<Integer, WidgetInfo> widgetInfos = new HashMap<Integer, WidgetInfo>();
51     private int nextWidgetId = 1;
52     private boolean alwaysRecreateViewsDuringUpdate = false;
53 
bind(AppWidgetManager appWidgetManager, Context context)54     private static void bind(AppWidgetManager appWidgetManager, Context context) {
55         // todo: implement
56     }
57 
58 
59     /**
60      * Finds or creates an {@code AppWidgetManager} for the given {@code context}
61      *
62      * @param context the {@code context} for which to produce an assoicated {@code AppWidgetManager}
63      * @return the {@code AppWidgetManager} associated with the given {@code context}
64      */
65     @Implementation
getInstance(Context context)66     public static AppWidgetManager getInstance(Context context) {
67         return instances.getInstance(context);
68     }
69 
70     @Implementation
updateAppWidget(int[] appWidgetIds, RemoteViews views)71     public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
72         for (int appWidgetId : appWidgetIds) {
73             updateAppWidget(appWidgetId, views);
74         }
75     }
76 
77     /**
78      * Simulates updating an {@code AppWidget} with a new set of views
79      *
80      * @param appWidgetId id of widget
81      * @param views       views to update
82      */
83     @Implementation
updateAppWidget(int appWidgetId, RemoteViews views)84     public void updateAppWidget(int appWidgetId, RemoteViews views) {
85         WidgetInfo widgetInfo = getWidgetInfo(appWidgetId);
86         int layoutId = views.getLayoutId();
87         if (widgetInfo.layoutId != layoutId || alwaysRecreateViewsDuringUpdate) {
88             widgetInfo.view = createWidgetView(layoutId);
89             widgetInfo.layoutId = layoutId;
90         }
91         widgetInfo.lastRemoteViews = views;
92         views.reapply(context, widgetInfo.view);
93     }
94 
95     @Implementation
getAppWidgetIds(ComponentName provider)96     public int[] getAppWidgetIds(ComponentName provider) {
97         List<Integer> idList = new ArrayList<Integer>();
98         for (int id : widgetInfos.keySet()) {
99             WidgetInfo widgetInfo = widgetInfos.get(id);
100             String widgetClass = widgetInfo.appWidgetProvider.getClass().getName();
101             String widgetPackage = widgetInfo.appWidgetProvider.getClass().getPackage().getName();
102             if (provider.getClassName().equals(widgetClass) && provider.getPackageName().equals(widgetPackage)) {
103                 idList.add(id);
104             }
105         }
106         int ids[] = new int[idList.size()];
107         for (int i = 0; i < idList.size(); i++) {
108             ids[i] = idList.get(i);
109         }
110         return ids;
111     }
112 
113     /**
114      * Triggers a reapplication of the most recent set of actions against the widget, which is what happens when the
115      * phone is rotated. Does not attempt to simulate a change in screen geometry.
116      *
117      * @param appWidgetId the ID of the widget to be affected
118      */
reconstructWidgetViewAsIfPhoneWasRotated(int appWidgetId)119     public void reconstructWidgetViewAsIfPhoneWasRotated(int appWidgetId) {
120         WidgetInfo widgetInfo = getWidgetInfo(appWidgetId);
121         widgetInfo.view = createWidgetView(widgetInfo.layoutId);
122         widgetInfo.lastRemoteViews.reapply(context, widgetInfo.view);
123     }
124 
125     /**
126      * Creates a widget by inflating its layout.
127      *
128      * @param appWidgetProviderClass the app widget provider class
129      * @param widgetLayoutId         id of the layout to inflate
130      * @return the ID of the new widget
131      */
createWidget(Class<? extends AppWidgetProvider> appWidgetProviderClass, int widgetLayoutId)132     public int createWidget(Class<? extends AppWidgetProvider> appWidgetProviderClass, int widgetLayoutId) {
133         return createWidgets(appWidgetProviderClass, widgetLayoutId, 1)[0];
134     }
135 
136     /**
137      * Creates a bunch of widgets by inflating the same layout multiple times.
138      *
139      * @param appWidgetProviderClass the app widget provider class
140      * @param widgetLayoutId         id of the layout to inflate
141      * @param howManyToCreate        number of new widgets to create
142      * @return the IDs of the new widgets
143      */
createWidgets(Class<? extends AppWidgetProvider> appWidgetProviderClass, int widgetLayoutId, int howManyToCreate)144     public int[] createWidgets(Class<? extends AppWidgetProvider> appWidgetProviderClass, int widgetLayoutId, int howManyToCreate) {
145         AppWidgetProvider appWidgetProvider = newInstanceOf(appWidgetProviderClass);
146 
147         int[] newWidgetIds = new int[howManyToCreate];
148         for (int i = 0; i < howManyToCreate; i++) {
149             View widgetView = createWidgetView(widgetLayoutId);
150 
151             int myWidgetId = nextWidgetId++;
152             widgetInfos.put(myWidgetId, new WidgetInfo(widgetView, widgetLayoutId, appWidgetProvider));
153             newWidgetIds[i] = myWidgetId;
154         }
155 
156         appWidgetProvider.onUpdate(context, realAppWidgetManager, newWidgetIds);
157         return newWidgetIds;
158     }
159 
createWidgetProvider(Class<? extends AppWidgetProvider> appWidgetProviderClass, int... newWidgetIds)160     private void createWidgetProvider(Class<? extends AppWidgetProvider> appWidgetProviderClass, int... newWidgetIds) {
161         AppWidgetProvider appWidgetProvider = newInstanceOf(appWidgetProviderClass);
162         appWidgetProvider.onUpdate(context, realAppWidgetManager, newWidgetIds);
163     }
164 
createWidgetView(int widgetLayoutId)165     private View createWidgetView(int widgetLayoutId) {
166         return new Activity().getLayoutInflater().inflate(widgetLayoutId, null);
167     }
168 
169     /**
170      * Non-Android accessor.
171      *
172      * @param widgetId id of the desired widget
173      * @return the widget associated with {@code widgetId}
174      */
getViewFor(int widgetId)175     public View getViewFor(int widgetId) {
176         return getWidgetInfo(widgetId).view;
177     }
178 
179     /**
180      * Non-Android accessor.
181      *
182      * @param widgetId id of the widget whose provider is to be returned
183      * @return the {@code AppWidgetProvider} associated with {@code widgetId}
184      */
getAppWidgetProviderFor(int widgetId)185     public AppWidgetProvider getAppWidgetProviderFor(int widgetId) {
186         return getWidgetInfo(widgetId).appWidgetProvider;
187     }
188 
189     /**
190      * Non-Android mechanism that enables testing of widget behavior when all of the views are recreated on every
191      * update. This is useful for ensuring that your widget will behave correctly even if it is restarted by the OS
192      * between events.
193      *
194      * @param alwaysRecreate whether or not to always recreate the views
195      */
setAlwaysRecreateViewsDuringUpdate(boolean alwaysRecreate)196     public void setAlwaysRecreateViewsDuringUpdate(boolean alwaysRecreate) {
197         alwaysRecreateViewsDuringUpdate = alwaysRecreate;
198     }
199 
200     /**
201      * Non-Android accessor.
202      *
203      * @return the state of the{@code alwaysRecreateViewsDuringUpdate} flag
204      */
getAlwaysRecreateViewsDuringUpdate()205     public boolean getAlwaysRecreateViewsDuringUpdate() {
206         return alwaysRecreateViewsDuringUpdate;
207     }
208 
getWidgetInfo(int widgetId)209     private WidgetInfo getWidgetInfo(int widgetId) {
210         return widgetInfos.get(widgetId);
211     }
212 
213     private class WidgetInfo {
214         private View view;
215         private int layoutId;
216         private AppWidgetProvider appWidgetProvider;
217         private RemoteViews lastRemoteViews;
218 
WidgetInfo(View view, int layoutId, AppWidgetProvider appWidgetProvider)219         public WidgetInfo(View view, int layoutId, AppWidgetProvider appWidgetProvider) {
220             this.view = view;
221             this.layoutId = layoutId;
222             this.appWidgetProvider = appWidgetProvider;
223         }
224     }
225 }
226