Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2009 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 
     17 package com.android.settings;
     18 
     19 import android.appwidget.AppWidgetManager;
     20 import android.appwidget.AppWidgetProviderInfo;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.Intent;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.PackageManager.NameNotFoundException;
     26 import android.content.res.Resources;
     27 import android.graphics.drawable.Drawable;
     28 import android.os.Bundle;
     29 import android.util.DisplayMetrics;
     30 import android.util.Log;
     31 
     32 import com.android.settings.ActivityPicker.PickAdapter;
     33 
     34 import java.util.List;
     35 
     36 /**
     37  * Displays a list of {@link AppWidgetProviderInfo} widgets, along with any
     38  * injected special widgets specified through
     39  * {@link AppWidgetManager#EXTRA_CUSTOM_INFO} and
     40  * {@link AppWidgetManager#EXTRA_CUSTOM_EXTRAS}.
     41  * <p>
     42  * When an installed {@link AppWidgetProviderInfo} is selected, this activity
     43  * will bind it to the given {@link AppWidgetManager#EXTRA_APPWIDGET_ID},
     44  * otherwise it will return the requested extras.
     45  */
     46 public class AppWidgetPickActivity extends ActivityPicker
     47     implements AppWidgetLoader.ItemConstructor<PickAdapter.Item>{
     48     private static final String TAG = "AppWidgetPickActivity";
     49     static final boolean LOGD = false;
     50 
     51     List<PickAdapter.Item> mItems;
     52 
     53     /**
     54      * The allocated {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that this
     55      * activity is binding.
     56      */
     57     private int mAppWidgetId;
     58     private AppWidgetLoader<PickAdapter.Item> mAppWidgetLoader;
     59     private AppWidgetManager mAppWidgetManager;
     60     private PackageManager mPackageManager;
     61 
     62     @Override
     63     public void onCreate(Bundle icicle) {
     64         mPackageManager = getPackageManager();
     65         mAppWidgetManager = AppWidgetManager.getInstance(this);
     66         mAppWidgetLoader = new AppWidgetLoader<PickAdapter.Item>
     67             (this, mAppWidgetManager, this);
     68 
     69         super.onCreate(icicle);
     70 
     71         // Set default return data
     72         setResultData(RESULT_CANCELED, null);
     73 
     74         // Read the appWidgetId passed our direction, otherwise bail if not found
     75         final Intent intent = getIntent();
     76         if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
     77             mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
     78                     AppWidgetManager.INVALID_APPWIDGET_ID);
     79         } else {
     80             finish();
     81         }
     82     }
     83 
     84     /**
     85      * Build and return list of items to be shown in dialog. This will mix both
     86      * installed {@link AppWidgetProviderInfo} and those provided through
     87      * {@link AppWidgetManager#EXTRA_CUSTOM_INFO}, sorting them alphabetically.
     88      */
     89     @Override
     90     protected List<PickAdapter.Item> getItems() {
     91         mItems = mAppWidgetLoader.getItems(getIntent());
     92         return mItems;
     93     }
     94 
     95     @Override
     96     public PickAdapter.Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras) {
     97         CharSequence label = info.label;
     98         Drawable icon = null;
     99 
    100         if (info.icon != 0) {
    101             try {
    102                 final Resources res = context.getResources();
    103                 final int density = res.getDisplayMetrics().densityDpi;
    104                 int iconDensity;
    105                 switch (density) {
    106                     case DisplayMetrics.DENSITY_MEDIUM:
    107                         iconDensity = DisplayMetrics.DENSITY_LOW;
    108                     case DisplayMetrics.DENSITY_TV:
    109                         iconDensity = DisplayMetrics.DENSITY_MEDIUM;
    110                     case DisplayMetrics.DENSITY_HIGH:
    111                         iconDensity = DisplayMetrics.DENSITY_MEDIUM;
    112                     case DisplayMetrics.DENSITY_XHIGH:
    113                         iconDensity = DisplayMetrics.DENSITY_HIGH;
    114                     case DisplayMetrics.DENSITY_XXHIGH:
    115                         iconDensity = DisplayMetrics.DENSITY_XHIGH;
    116                     default:
    117                         // The density is some abnormal value.  Return some other
    118                         // abnormal value that is a reasonable scaling of it.
    119                         iconDensity = (int)((density*0.75f)+.5f);
    120                 }
    121                 Resources packageResources = mPackageManager.
    122                         getResourcesForApplication(info.provider.getPackageName());
    123                 icon = packageResources.getDrawableForDensity(info.icon, iconDensity);
    124             } catch (NameNotFoundException e) {
    125                 Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
    126                         + " for provider: " + info.provider);
    127             }
    128             if (icon == null) {
    129                 Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
    130                         + " for provider: " + info.provider);
    131             }
    132         }
    133 
    134         PickAdapter.Item item = new PickAdapter.Item(context, label, icon);
    135         item.packageName = info.provider.getPackageName();
    136         item.className = info.provider.getClassName();
    137         item.extras = extras;
    138         return item;
    139     }
    140 
    141     /**
    142      * {@inheritDoc}
    143      */
    144     @Override
    145     public void onClick(DialogInterface dialog, int which) {
    146         Intent intent = getIntentForPosition(which);
    147         PickAdapter.Item item = mItems.get(which);
    148 
    149         int result;
    150         if (item.extras != null) {
    151             // If these extras are present it's because this entry is custom.
    152             // Don't try to bind it, just pass it back to the app.
    153             setResultData(RESULT_OK, intent);
    154         } else {
    155             try {
    156                 Bundle options = null;
    157                 if (intent.getExtras() != null) {
    158                     options = intent.getExtras().getBundle(
    159                             AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
    160                 }
    161                 mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent(), options);
    162                 result = RESULT_OK;
    163             } catch (IllegalArgumentException e) {
    164                 // This is thrown if they're already bound, or otherwise somehow
    165                 // bogus.  Set the result to canceled, and exit.  The app *should*
    166                 // clean up at this point.  We could pass the error along, but
    167                 // it's not clear that that's useful -- the widget will simply not
    168                 // appear.
    169                 result = RESULT_CANCELED;
    170             }
    171             setResultData(result, null);
    172         }
    173 
    174         finish();
    175     }
    176 
    177 
    178     /**
    179      * Convenience method for setting the result code and intent. This method
    180      * correctly injects the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that
    181      * most hosts expect returned.
    182      */
    183     void setResultData(int code, Intent intent) {
    184         Intent result = intent != null ? intent : new Intent();
    185         result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
    186         setResult(code, result);
    187     }
    188 }
    189