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