1afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/* 2173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * Copyright (C) 2009 The Android Open Source Project 3afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 4afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * you may not use this file except in compliance with the License. 6afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * You may obtain a copy of the License at 7afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 8afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * 10afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * See the License for the specific language governing permissions and 14afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * limitations under the License. 15afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */ 16afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 17afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectpackage com.android.settings; 18afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 1980a7a1dbf22d689723d39bad9ba319b6f4b0201dThe Android Open Source Projectimport android.appwidget.AppWidgetManager; 2080a7a1dbf22d689723d39bad9ba319b6f4b0201dThe Android Open Source Projectimport android.appwidget.AppWidgetProviderInfo; 210b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurkaimport android.content.Context; 22173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkeyimport android.content.DialogInterface; 23afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.Intent; 24afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.content.pm.PackageManager; 2516398c9c973ba16a14455c4eee9ca162e0273792Michael Jurkaimport android.content.pm.PackageManager.NameNotFoundException; 2616398c9c973ba16a14455c4eee9ca162e0273792Michael Jurkaimport android.content.res.Resources; 27afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.graphics.drawable.Drawable; 28afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.os.Bundle; 2916398c9c973ba16a14455c4eee9ca162e0273792Michael Jurkaimport android.util.DisplayMetrics; 30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.util.Log; 31afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 320b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurkaimport com.android.settings.ActivityPicker.PickAdapter; 330b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka 3416398c9c973ba16a14455c4eee9ca162e0273792Michael Jurkaimport java.util.List; 35afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 36173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey/** 37173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * Displays a list of {@link AppWidgetProviderInfo} widgets, along with any 38173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * injected special widgets specified through 39173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * {@link AppWidgetManager#EXTRA_CUSTOM_INFO} and 40173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * {@link AppWidgetManager#EXTRA_CUSTOM_EXTRAS}. 41173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * <p> 42173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * When an installed {@link AppWidgetProviderInfo} is selected, this activity 43173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * will bind it to the given {@link AppWidgetManager#EXTRA_APPWIDGET_ID}, 44173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * otherwise it will return the requested extras. 45173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey */ 460b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurkapublic class AppWidgetPickActivity extends ActivityPicker 470b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka implements AppWidgetLoader.ItemConstructor<PickAdapter.Item>{ 4880a7a1dbf22d689723d39bad9ba319b6f4b0201dThe Android Open Source Project private static final String TAG = "AppWidgetPickActivity"; 490b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka static final boolean LOGD = false; 50afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 5116398c9c973ba16a14455c4eee9ca162e0273792Michael Jurka List<PickAdapter.Item> mItems; 52173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey 53173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey /** 54173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * The allocated {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that this 55173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * activity is binding. 56173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey */ 57173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey private int mAppWidgetId; 580b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka private AppWidgetLoader<PickAdapter.Item> mAppWidgetLoader; 590b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka private AppWidgetManager mAppWidgetManager; 600b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka private PackageManager mPackageManager; 61f8f6217f962a6682548502b6cc4b10e2dc9a144fJim Miller 62afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 63afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project public void onCreate(Bundle icicle) { 64173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey mPackageManager = getPackageManager(); 65173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey mAppWidgetManager = AppWidgetManager.getInstance(this); 660b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka mAppWidgetLoader = new AppWidgetLoader<PickAdapter.Item> 670b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka (this, mAppWidgetManager, this); 68173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey 69173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey super.onCreate(icicle); 70173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey 71173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey // Set default return data 72173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey setResultData(RESULT_CANCELED, null); 73173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey 74173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey // Read the appWidgetId passed our direction, otherwise bail if not found 75173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey final Intent intent = getIntent(); 76173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { 77173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 78173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey AppWidgetManager.INVALID_APPWIDGET_ID); 79173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey } else { 80e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project finish(); 81e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 82173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey } 838291c08c952b05f11efb22aa4079892cdb408daaAdam Cohen 84173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey /** 850b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka * Build and return list of items to be shown in dialog. This will mix both 860b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka * installed {@link AppWidgetProviderInfo} and those provided through 870b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically. 88173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey */ 890b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka @Override 900b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka protected List<PickAdapter.Item> getItems() { 910b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka mItems = mAppWidgetLoader.getItems(getIntent()); 920b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka return mItems; 930b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka } 94e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 950b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka @Override 960b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka public PickAdapter.Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras) { 970b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka CharSequence label = info.label; 980b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka Drawable icon = null; 99e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 1000b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka if (info.icon != 0) { 1010b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka try { 1020b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka final Resources res = context.getResources(); 1030b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka final int density = res.getDisplayMetrics().densityDpi; 1040b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka int iconDensity; 1050b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka switch (density) { 1060b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka case DisplayMetrics.DENSITY_MEDIUM: 1070b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka iconDensity = DisplayMetrics.DENSITY_LOW; 1080b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka case DisplayMetrics.DENSITY_TV: 1090b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka iconDensity = DisplayMetrics.DENSITY_MEDIUM; 1100b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka case DisplayMetrics.DENSITY_HIGH: 1110b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka iconDensity = DisplayMetrics.DENSITY_MEDIUM; 1120b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka case DisplayMetrics.DENSITY_XHIGH: 1130b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka iconDensity = DisplayMetrics.DENSITY_HIGH; 1140b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka case DisplayMetrics.DENSITY_XXHIGH: 1150b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka iconDensity = DisplayMetrics.DENSITY_XHIGH; 1160b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka default: 1170b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka // The density is some abnormal value. Return some other 1180b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka // abnormal value that is a reasonable scaling of it. 1190b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka iconDensity = (int)((density*0.75f)+.5f); 120e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 1210b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka Resources packageResources = mPackageManager. 1220b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka getResourcesForApplication(info.provider.getPackageName()); 1230b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka icon = packageResources.getDrawableForDensity(info.icon, iconDensity); 1240b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka } catch (NameNotFoundException e) { 1250b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon) 1260b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka + " for provider: " + info.provider); 1270b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka } 1280b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka if (icon == null) { 1290b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon) 1300b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka + " for provider: " + info.provider); 131e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 132e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 133e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project 1340b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka PickAdapter.Item item = new PickAdapter.Item(context, label, icon); 1350b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka item.packageName = info.provider.getPackageName(); 1360b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka item.className = info.provider.getClassName(); 1370b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka item.extras = extras; 1380b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka return item; 139afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1400b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka 141173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey /** 142173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * {@inheritDoc} 143173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey */ 144afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project @Override 145173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey public void onClick(DialogInterface dialog, int which) { 146173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey Intent intent = getIntentForPosition(which); 1470b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka PickAdapter.Item item = mItems.get(which); 14885d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen 149afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project int result; 15016398c9c973ba16a14455c4eee9ca162e0273792Michael Jurka if (item.extras != null) { 15185d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen // If these extras are present it's because this entry is custom. 152e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // Don't try to bind it, just pass it back to the app. 153e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project setResultData(RESULT_OK, intent); 154e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } else { 155e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project try { 15685d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen Bundle options = null; 15785d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen if (intent.getExtras() != null) { 15885d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen options = intent.getExtras().getBundle( 15985d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen AppWidgetManager.EXTRA_APPWIDGET_OPTIONS); 16085d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen } 16185d4b5f78e831fdfe6da39f6edafd32c7d63dfeaAdam Cohen mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent(), options); 162e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project result = RESULT_OK; 163e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } catch (IllegalArgumentException e) { 164e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // This is thrown if they're already bound, or otherwise somehow 165e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // bogus. Set the result to canceled, and exit. The app *should* 166e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // clean up at this point. We could pass the error along, but 167e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // it's not clear that that's useful -- the widget will simply not 168e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project // appear. 169e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project result = RESULT_CANCELED; 170e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project } 171e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project setResultData(result, null); 172afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 1738227e303850d7c1162c62947b70d0592432b455eMichael Jurka 1740b2bd8d11d6947a6ce71db0691ba341aec7a2964Michael Jurka finish(); 175afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 176afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project 177173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey 178173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey /** 179173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * Convenience method for setting the result code and intent. This method 180173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * correctly injects the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that 181173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey * most hosts expect returned. 182173545e63b5078d9d0e194552e39bb5e9f358082Jeffrey Sharkey */ 183e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project void setResultData(int code, Intent intent) { 184e6dd1fa1851302710ac7845d25d8ad8a5b6ee438The Android Open Source Project Intent result = intent != null ? intent : new Intent(); 18580a7a1dbf22d689723d39bad9ba319b6f4b0201dThe Android Open Source Project result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); 186afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project setResult(code, result); 187afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project } 188afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project} 189