1/* 2 * Copyright (C) 2012 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 17package com.android.settings; 18 19import android.appwidget.AppWidgetManager; 20import android.appwidget.AppWidgetProviderInfo; 21import android.content.Context; 22import android.content.Intent; 23import android.os.Bundle; 24import android.os.Parcelable; 25import android.util.Log; 26 27import java.text.Collator; 28import java.util.ArrayList; 29import java.util.Collections; 30import java.util.Comparator; 31import java.util.List; 32 33public class AppWidgetLoader<Item extends AppWidgetLoader.LabelledItem> { 34 private static final String TAG = "AppWidgetAdapter"; 35 private static final boolean LOGD = AppWidgetPickActivity.LOGD; 36 37 private Context mContext; 38 private AppWidgetManager mAppWidgetManager; 39 ItemConstructor<Item> mItemConstructor; 40 41 interface LabelledItem { 42 CharSequence getLabel(); 43 } 44 45 public AppWidgetLoader(Context context, AppWidgetManager appWidgetManager, 46 ItemConstructor<Item> itemConstructor) { 47 mContext = context; 48 mAppWidgetManager = appWidgetManager; 49 mItemConstructor = itemConstructor; 50 } 51 52 /** 53 * Create list entries for any custom widgets requested through 54 * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}. 55 */ 56 void putCustomAppWidgets(List<Item> items, Intent intent) { 57 // get and validate the extras they gave us 58 ArrayList<AppWidgetProviderInfo> customInfo = null; 59 ArrayList<Bundle> customExtras = null; 60 try_custom_items: { 61 customInfo = intent.getParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO); 62 if (customInfo == null || customInfo.size() == 0) { 63 Log.i(TAG, "EXTRA_CUSTOM_INFO not present."); 64 break try_custom_items; 65 } 66 67 int customInfoSize = customInfo.size(); 68 for (int i=0; i<customInfoSize; i++) { 69 Parcelable p = customInfo.get(i); 70 if (p == null || !(p instanceof AppWidgetProviderInfo)) { 71 customInfo = null; 72 Log.e(TAG, "error using EXTRA_CUSTOM_INFO index=" + i); 73 break try_custom_items; 74 } 75 } 76 77 customExtras = intent.getParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS); 78 if (customExtras == null) { 79 customInfo = null; 80 Log.e(TAG, "EXTRA_CUSTOM_INFO without EXTRA_CUSTOM_EXTRAS"); 81 break try_custom_items; 82 } 83 84 int customExtrasSize = customExtras.size(); 85 if (customInfoSize != customExtrasSize) { 86 customInfo = null; 87 customExtras = null; 88 Log.e(TAG, "list size mismatch: EXTRA_CUSTOM_INFO: " + customInfoSize 89 + " EXTRA_CUSTOM_EXTRAS: " + customExtrasSize); 90 break try_custom_items; 91 } 92 93 94 for (int i=0; i<customExtrasSize; i++) { 95 Parcelable p = customExtras.get(i); 96 if (p == null || !(p instanceof Bundle)) { 97 customInfo = null; 98 customExtras = null; 99 Log.e(TAG, "error using EXTRA_CUSTOM_EXTRAS index=" + i); 100 break try_custom_items; 101 } 102 } 103 } 104 105 if (LOGD) Log.d(TAG, "Using " + customInfo.size() + " custom items"); 106 putAppWidgetItems(customInfo, customExtras, items, 0, true); 107 } 108 109 110 /** 111 * Create list entries for the given {@link AppWidgetProviderInfo} widgets, 112 * inserting extras if provided. 113 */ 114 void putAppWidgetItems(List<AppWidgetProviderInfo> appWidgets, 115 List<Bundle> customExtras, List<Item> items, int categoryFilter, 116 boolean ignoreFilter) { 117 if (appWidgets == null) return; 118 final int size = appWidgets.size(); 119 for (int i = 0; i < size; i++) { 120 AppWidgetProviderInfo info = appWidgets.get(i); 121 122 // We remove any widgets whose category isn't included in the filter 123 if (!ignoreFilter && (info.widgetCategory & categoryFilter) == 0) { 124 continue; 125 } 126 127 Item item = mItemConstructor.createItem(mContext, info, 128 customExtras != null ? customExtras.get(i) : null); 129 130 items.add(item); 131 } 132 } 133 134 public interface ItemConstructor<Item> { 135 Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras); 136 } 137 138 139 /** 140 * Build and return list of items to be shown in dialog. This will mix both 141 * installed {@link AppWidgetProviderInfo} and those provided through 142 * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically. 143 */ 144 protected List<Item> getItems(Intent intent) { 145 boolean sortCustomAppWidgets = 146 intent.getBooleanExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, true); 147 148 List<Item> items = new ArrayList<Item>(); 149 150 // Default category is home screen 151 int categoryFilter = intent.getIntExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER, 152 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 153 154 putInstalledAppWidgets(items, categoryFilter); 155 156 // Sort all items together by label 157 if (sortCustomAppWidgets) { 158 putCustomAppWidgets(items, intent); 159 } 160 Collections.sort(items, new Comparator<Item>() { 161 Collator mCollator = Collator.getInstance(); 162 163 public int compare(Item lhs, Item rhs) { 164 return mCollator.compare(lhs.getLabel(), rhs.getLabel()); 165 } 166 }); 167 if (!sortCustomAppWidgets) { 168 List<Item> customItems = new ArrayList<Item>(); 169 putCustomAppWidgets(customItems, intent); 170 items.addAll(customItems); 171 } 172 return items; 173 } 174 175 /** 176 * Create list entries for installed {@link AppWidgetProviderInfo} widgets. 177 */ 178 void putInstalledAppWidgets(List<Item> items, int categoryFilter) { 179 List<AppWidgetProviderInfo> installed = 180 mAppWidgetManager.getInstalledProviders(categoryFilter); 181 putAppWidgetItems(installed, null, items, categoryFilter, false); 182 } 183} 184