Home | History | Annotate | Download | only in settings
      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 
     17 package com.android.settings;
     18 
     19 import android.app.Activity;
     20 import android.app.ActivityManager;
     21 import android.app.LauncherActivity.IconResizer;
     22 import android.appwidget.AppWidgetHost;
     23 import android.appwidget.AppWidgetManager;
     24 import android.appwidget.AppWidgetProviderInfo;
     25 import android.content.ActivityNotFoundException;
     26 import android.content.ComponentName;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.pm.PackageManager;
     30 import android.content.res.Resources;
     31 import android.graphics.Bitmap;
     32 import android.graphics.Bitmap.Config;
     33 import android.graphics.Canvas;
     34 import android.graphics.Paint;
     35 import android.graphics.Rect;
     36 import android.graphics.drawable.Drawable;
     37 import android.os.AsyncTask;
     38 import android.os.Bundle;
     39 import android.os.IBinder;
     40 import android.os.RemoteException;
     41 import android.os.ServiceManager;
     42 import android.os.UserHandle;
     43 import android.util.DisplayMetrics;
     44 import android.util.Log;
     45 import android.view.IWindowManager;
     46 import android.view.LayoutInflater;
     47 import android.view.View;
     48 import android.view.ViewGroup;
     49 import android.widget.AdapterView;
     50 import android.widget.BaseAdapter;
     51 import android.widget.GridView;
     52 import android.widget.ImageView;
     53 import android.widget.TextView;
     54 import android.widget.Toast;
     55 
     56 import com.android.internal.widget.LockPatternUtils;
     57 
     58 import java.lang.ref.WeakReference;
     59 import java.util.List;
     60 
     61 /**
     62  * Displays a list of {@link AppWidgetProviderInfo} widgets, along with any
     63  * injected special widgets specified through
     64  * {@link AppWidgetManager#EXTRA_CUSTOM_INFO} and
     65  * {@link AppWidgetManager#EXTRA_CUSTOM_EXTRAS}.
     66  * <p>
     67  * When an installed {@link AppWidgetProviderInfo} is selected, this activity
     68  * will bind it to the given {@link AppWidgetManager#EXTRA_APPWIDGET_ID},
     69  * otherwise it will return the requested extras.
     70  */
     71 public class KeyguardAppWidgetPickActivity extends Activity
     72     implements GridView.OnItemClickListener,
     73         AppWidgetLoader.ItemConstructor<KeyguardAppWidgetPickActivity.Item> {
     74     private static final String TAG = "KeyguardAppWidgetPickActivity";
     75     private static final int REQUEST_PICK_APPWIDGET = 126;
     76     private static final int REQUEST_CREATE_APPWIDGET = 127;
     77 
     78     private AppWidgetLoader<Item> mAppWidgetLoader;
     79     private List<Item> mItems;
     80     private GridView mGridView;
     81     private AppWidgetAdapter mAppWidgetAdapter;
     82     private AppWidgetManager mAppWidgetManager;
     83     private int mAppWidgetId;
     84     // Might make it possible to make this be false in future
     85     private boolean mAddingToKeyguard = true;
     86     private Intent mResultData;
     87     private LockPatternUtils mLockPatternUtils;
     88     private Bundle mExtraConfigureOptions;
     89 
     90     @Override
     91     protected void onCreate(Bundle savedInstanceState) {
     92         setContentView(R.layout.keyguard_appwidget_picker_layout);
     93         super.onCreate(savedInstanceState);
     94 
     95         // Set default return data
     96         setResultData(RESULT_CANCELED, null);
     97 
     98         // Read the appWidgetId passed our direction, otherwise bail if not found
     99         final Intent intent = getIntent();
    100         if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
    101             mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
    102                     AppWidgetManager.INVALID_APPWIDGET_ID);
    103         } else {
    104             finish();
    105         }
    106         mExtraConfigureOptions = intent.getBundleExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
    107 
    108         mGridView = (GridView) findViewById(R.id.widget_list);
    109         DisplayMetrics dm = new DisplayMetrics();
    110         getWindowManager().getDefaultDisplay().getMetrics(dm);
    111         int maxGridWidth = getResources().getDimensionPixelSize(
    112                 R.dimen.keyguard_appwidget_picker_max_width);
    113 
    114         if (maxGridWidth < dm.widthPixels) {
    115             mGridView.getLayoutParams().width = maxGridWidth;
    116         }
    117         mAppWidgetManager = AppWidgetManager.getInstance(this);
    118         mAppWidgetLoader = new AppWidgetLoader<Item>(this, mAppWidgetManager, this);
    119         mItems = mAppWidgetLoader.getItems(getIntent());
    120         mAppWidgetAdapter = new AppWidgetAdapter(this, mItems);
    121         mGridView.setAdapter(mAppWidgetAdapter);
    122         mGridView.setOnItemClickListener(this);
    123 
    124         mLockPatternUtils = new LockPatternUtils(this); // TEMP-- we want to delete this
    125     }
    126 
    127     /**
    128      * Convenience method for setting the result code and intent. This method
    129      * correctly injects the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} that
    130      * most hosts expect returned.
    131      */
    132     void setResultData(int code, Intent intent) {
    133         Intent result = intent != null ? intent : new Intent();
    134         result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
    135         mResultData = result;
    136         setResult(code, result);
    137     }
    138 
    139     /**
    140      * Item that appears in the AppWidget picker grid.
    141      */
    142     public static class Item implements AppWidgetLoader.LabelledItem {
    143         protected static IconResizer sResizer;
    144 
    145 
    146         CharSequence label;
    147         int appWidgetPreviewId;
    148         int iconId;
    149         String packageName;
    150         String className;
    151         Bundle extras;
    152         private WidgetPreviewLoader mWidgetPreviewLoader;
    153         private Context mContext;
    154 
    155         /**
    156          * Create a list item from given label and icon.
    157          */
    158         Item(Context context, CharSequence label) {
    159             this.label = label;
    160             mContext = context;
    161         }
    162 
    163         void loadWidgetPreview(ImageView v) {
    164             mWidgetPreviewLoader = new WidgetPreviewLoader(mContext, v);
    165             mWidgetPreviewLoader.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
    166         }
    167 
    168         void cancelLoadingWidgetPreview() {
    169             if (mWidgetPreviewLoader != null) {
    170                 mWidgetPreviewLoader.cancel(false);
    171                 mWidgetPreviewLoader = null;
    172             }
    173         }
    174 
    175         /**
    176          * Build the {@link Intent} described by this item. If this item
    177          * can't create a valid {@link android.content.ComponentName}, it will return
    178          * {@link Intent#ACTION_CREATE_SHORTCUT} filled with the item label.
    179          */
    180         Intent getIntent() {
    181             Intent intent = new Intent();
    182             if (packageName != null && className != null) {
    183                 // Valid package and class, so fill details as normal intent
    184                 intent.setClassName(packageName, className);
    185                 if (extras != null) {
    186                     intent.putExtras(extras);
    187                 }
    188             } else {
    189                 // No valid package or class, so treat as shortcut with label
    190                 intent.setAction(Intent.ACTION_CREATE_SHORTCUT);
    191                 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label);
    192             }
    193             return intent;
    194         }
    195 
    196         public CharSequence getLabel() {
    197             return label;
    198         }
    199 
    200         class WidgetPreviewLoader extends AsyncTask<Void, Bitmap, Void> {
    201             private Resources mResources;
    202             private PackageManager mPackageManager;
    203             private int mIconDpi;
    204             private ImageView mView;
    205             public WidgetPreviewLoader(Context context, ImageView v) {
    206                 super();
    207                 mResources = context.getResources();
    208                 mPackageManager = context.getPackageManager();
    209                 ActivityManager activityManager =
    210                         (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    211                 mIconDpi = activityManager.getLauncherLargeIconDensity();
    212                 mView = v;
    213             }
    214             public Void doInBackground(Void... params) {
    215                 if (!isCancelled()) {
    216                     int appWidgetPreviewWidth =
    217                             mResources.getDimensionPixelSize(R.dimen.appwidget_preview_width);
    218                     int appWidgetPreviewHeight =
    219                             mResources.getDimensionPixelSize(R.dimen.appwidget_preview_height);
    220                     Bitmap b = getWidgetPreview(new ComponentName(packageName, className),
    221                             appWidgetPreviewId, iconId,
    222                             appWidgetPreviewWidth, appWidgetPreviewHeight);
    223                     publishProgress(b);
    224                 }
    225                 return null;
    226             }
    227             public void onProgressUpdate(Bitmap... values) {
    228                 if (!isCancelled()) {
    229                     Bitmap b = values[0];
    230                     mView.setImageBitmap(b);
    231                 }
    232             }
    233             abstract class WeakReferenceThreadLocal<T> {
    234                 private ThreadLocal<WeakReference<T>> mThreadLocal;
    235                 public WeakReferenceThreadLocal() {
    236                     mThreadLocal = new ThreadLocal<WeakReference<T>>();
    237                 }
    238 
    239                 abstract T initialValue();
    240 
    241                 public void set(T t) {
    242                     mThreadLocal.set(new WeakReference<T>(t));
    243                 }
    244 
    245                 public T get() {
    246                     WeakReference<T> reference = mThreadLocal.get();
    247                     T obj;
    248                     if (reference == null) {
    249                         obj = initialValue();
    250                         mThreadLocal.set(new WeakReference<T>(obj));
    251                         return obj;
    252                     } else {
    253                         obj = reference.get();
    254                         if (obj == null) {
    255                             obj = initialValue();
    256                             mThreadLocal.set(new WeakReference<T>(obj));
    257                         }
    258                         return obj;
    259                     }
    260                 }
    261             }
    262 
    263             class CanvasCache extends WeakReferenceThreadLocal<Canvas> {
    264                 @Override
    265                 protected Canvas initialValue() {
    266                     return new Canvas();
    267                 }
    268             }
    269 
    270             class PaintCache extends WeakReferenceThreadLocal<Paint> {
    271                 @Override
    272                 protected Paint initialValue() {
    273                     return null;
    274                 }
    275             }
    276 
    277             class BitmapCache extends WeakReferenceThreadLocal<Bitmap> {
    278                 @Override
    279                 protected Bitmap initialValue() {
    280                     return null;
    281                 }
    282             }
    283 
    284             class RectCache extends WeakReferenceThreadLocal<Rect> {
    285                 @Override
    286                 protected Rect initialValue() {
    287                     return new Rect();
    288                 }
    289             }
    290 
    291             // Used for drawing widget previews
    292             CanvasCache sCachedAppWidgetPreviewCanvas = new CanvasCache();
    293             RectCache sCachedAppWidgetPreviewSrcRect = new RectCache();
    294             RectCache sCachedAppWidgetPreviewDestRect = new RectCache();
    295             PaintCache sCachedAppWidgetPreviewPaint = new PaintCache();
    296 
    297             private Bitmap getWidgetPreview(ComponentName provider, int previewImage,
    298                     int iconId, int maxWidth, int maxHeight) {
    299                 // Load the preview image if possible
    300                 String packageName = provider.getPackageName();
    301                 if (maxWidth < 0) maxWidth = Integer.MAX_VALUE;
    302                 if (maxHeight < 0) maxHeight = Integer.MAX_VALUE;
    303 
    304 
    305                 int appIconSize = mResources.getDimensionPixelSize(R.dimen.app_icon_size);
    306 
    307                 Drawable drawable = null;
    308                 if (previewImage != 0) {
    309                     drawable = mPackageManager.getDrawable(packageName, previewImage, null);
    310                     if (drawable == null) {
    311                         Log.w(TAG, "Can't load widget preview drawable 0x" +
    312                                 Integer.toHexString(previewImage) + " for provider: " + provider);
    313                     }
    314                 }
    315 
    316                 int bitmapWidth;
    317                 int bitmapHeight;
    318                 Bitmap defaultPreview = null;
    319                 boolean widgetPreviewExists = (drawable != null);
    320                 if (widgetPreviewExists) {
    321                     bitmapWidth = drawable.getIntrinsicWidth();
    322                     bitmapHeight = drawable.getIntrinsicHeight();
    323                 } else {
    324                     // Generate a preview image if we couldn't load one
    325                     bitmapWidth = appIconSize;
    326                     bitmapHeight = appIconSize;
    327                     defaultPreview = Bitmap.createBitmap(bitmapWidth, bitmapHeight,
    328                             Config.ARGB_8888);
    329 
    330                     try {
    331                         Drawable icon = null;
    332                         if (iconId > 0)
    333                             icon = getFullResIcon(packageName, iconId);
    334                         if (icon != null) {
    335                             renderDrawableToBitmap(icon, defaultPreview, 0,
    336                                     0, appIconSize, appIconSize);
    337                         }
    338                     } catch (Resources.NotFoundException e) {
    339                     }
    340                 }
    341 
    342                 // Scale to fit width only - let the widget preview be clipped in the
    343                 // vertical dimension
    344                 float scale = 1f;
    345                 if (bitmapWidth > maxWidth) {
    346                     scale = maxWidth / (float) bitmapWidth;
    347                 }
    348                 int finalPreviewWidth = (int) (scale * bitmapWidth);
    349                 int finalPreviewHeight = (int) (scale * bitmapHeight);
    350 
    351                 bitmapWidth = finalPreviewWidth;
    352                 bitmapHeight = Math.min(finalPreviewHeight, maxHeight);
    353 
    354                 Bitmap preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight,
    355                         Config.ARGB_8888);
    356 
    357                 // Draw the scaled preview into the final bitmap
    358                 if (widgetPreviewExists) {
    359                     renderDrawableToBitmap(drawable, preview, 0, 0, finalPreviewWidth,
    360                             finalPreviewHeight);
    361                 } else {
    362                     final Canvas c = sCachedAppWidgetPreviewCanvas.get();
    363                     final Rect src = sCachedAppWidgetPreviewSrcRect.get();
    364                     final Rect dest = sCachedAppWidgetPreviewDestRect.get();
    365                     c.setBitmap(preview);
    366                     src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight());
    367                     dest.set(0, 0, finalPreviewWidth, finalPreviewHeight);
    368 
    369                     Paint p = sCachedAppWidgetPreviewPaint.get();
    370                     if (p == null) {
    371                         p = new Paint();
    372                         p.setFilterBitmap(true);
    373                         sCachedAppWidgetPreviewPaint.set(p);
    374                     }
    375                     c.drawBitmap(defaultPreview, src, dest, p);
    376                     c.setBitmap(null);
    377                 }
    378                 return preview;
    379             }
    380             public Drawable getFullResDefaultActivityIcon() {
    381                 return getFullResIcon(Resources.getSystem(),
    382                         android.R.mipmap.sym_def_app_icon);
    383             }
    384 
    385             public Drawable getFullResIcon(Resources resources, int iconId) {
    386                 Drawable d;
    387                 try {
    388                     d = resources.getDrawableForDensity(iconId, mIconDpi);
    389                 } catch (Resources.NotFoundException e) {
    390                     d = null;
    391                 }
    392 
    393                 return (d != null) ? d : getFullResDefaultActivityIcon();
    394             }
    395 
    396             public Drawable getFullResIcon(String packageName, int iconId) {
    397                 Resources resources;
    398                 try {
    399                     resources = mPackageManager.getResourcesForApplication(packageName);
    400                 } catch (PackageManager.NameNotFoundException e) {
    401                     resources = null;
    402                 }
    403                 if (resources != null) {
    404                     if (iconId != 0) {
    405                         return getFullResIcon(resources, iconId);
    406                     }
    407                 }
    408                 return getFullResDefaultActivityIcon();
    409             }
    410 
    411             private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
    412                 renderDrawableToBitmap(d, bitmap, x, y, w, h, 1f);
    413             }
    414 
    415             private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h,
    416                     float scale) {
    417                 if (bitmap != null) {
    418                     Canvas c = new Canvas(bitmap);
    419                     c.scale(scale, scale);
    420                     Rect oldBounds = d.copyBounds();
    421                     d.setBounds(x, y, x + w, y + h);
    422                     d.draw(c);
    423                     d.setBounds(oldBounds); // Restore the bounds
    424                     c.setBitmap(null);
    425                 }
    426             }
    427         }
    428     }
    429 
    430     @Override
    431     public Item createItem(Context context, AppWidgetProviderInfo info, Bundle extras) {
    432         CharSequence label = info.label;
    433 
    434         Item item = new Item(context, label);
    435         item.appWidgetPreviewId = info.previewImage;
    436         item.iconId = info.icon;
    437         item.packageName = info.provider.getPackageName();
    438         item.className = info.provider.getClassName();
    439         item.extras = extras;
    440         return item;
    441     }
    442 
    443     protected static class AppWidgetAdapter extends BaseAdapter {
    444         private final LayoutInflater mInflater;
    445         private final List<Item> mItems;
    446 
    447         /**
    448          * Create an adapter for the given items.
    449          */
    450         public AppWidgetAdapter(Context context, List<Item> items) {
    451             mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    452             mItems = items;
    453         }
    454 
    455         /**
    456          * {@inheritDoc}
    457          */
    458         public int getCount() {
    459             return mItems.size();
    460         }
    461 
    462         /**
    463          * {@inheritDoc}
    464          */
    465         public Object getItem(int position) {
    466             return mItems.get(position);
    467         }
    468 
    469         /**
    470          * {@inheritDoc}
    471          */
    472         public long getItemId(int position) {
    473             return position;
    474         }
    475 
    476         /**
    477          * {@inheritDoc}
    478          */
    479         public View getView(int position, View convertView, ViewGroup parent) {
    480             if (convertView == null) {
    481                 convertView = mInflater.inflate(R.layout.keyguard_appwidget_item, parent, false);
    482             }
    483 
    484             Item item = (Item) getItem(position);
    485             TextView textView = (TextView) convertView.findViewById(R.id.label);
    486             textView.setText(item.label);
    487             ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
    488             iconView.setImageDrawable(null);
    489             item.loadWidgetPreview(iconView);
    490             return convertView;
    491         }
    492 
    493         public void cancelAllWidgetPreviewLoaders() {
    494             for (int i = 0; i < mItems.size(); i++) {
    495                 mItems.get(i).cancelLoadingWidgetPreview();
    496             }
    497         }
    498     }
    499 
    500     /**
    501      * {@inheritDoc}
    502      */
    503     @Override
    504     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    505         Item item = mItems.get(position);
    506         Intent intent = item.getIntent();
    507 
    508         int result;
    509         if (item.extras != null) {
    510             // If these extras are present it's because this entry is custom.
    511             // Don't try to bind it, just pass it back to the app.
    512             result = RESULT_OK;
    513             setResultData(result, intent);
    514         } else {
    515             try {
    516                 if (mAddingToKeyguard && mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
    517                     // Found in KeyguardHostView.java
    518                     final int KEYGUARD_HOST_ID = 0x4B455947;
    519                     int userId = ActivityManager.getCurrentUser();
    520                     mAppWidgetId = AppWidgetHost.allocateAppWidgetIdForSystem(KEYGUARD_HOST_ID,
    521                             userId);
    522                 }
    523                 mAppWidgetManager.bindAppWidgetId(
    524                         mAppWidgetId, intent.getComponent(), mExtraConfigureOptions);
    525                 result = RESULT_OK;
    526             } catch (IllegalArgumentException e) {
    527                 // This is thrown if they're already bound, or otherwise somehow
    528                 // bogus.  Set the result to canceled, and exit.  The app *should*
    529                 // clean up at this point.  We could pass the error along, but
    530                 // it's not clear that that's useful -- the widget will simply not
    531                 // appear.
    532                 result = RESULT_CANCELED;
    533             }
    534             setResultData(result, null);
    535         }
    536         if (mAddingToKeyguard) {
    537             onActivityResult(REQUEST_PICK_APPWIDGET, result, mResultData);
    538         } else {
    539             finish();
    540         }
    541     }
    542 
    543     protected void onDestroy() {
    544         if (mAppWidgetAdapter != null) {
    545             mAppWidgetAdapter.cancelAllWidgetPreviewLoaders();
    546         }
    547         super.onDestroy();
    548     }
    549 
    550     @Override
    551     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    552         super.onActivityResult(requestCode, resultCode, data);
    553         if (requestCode == REQUEST_PICK_APPWIDGET || requestCode == REQUEST_CREATE_APPWIDGET) {
    554             int appWidgetId;
    555             if  (data == null) {
    556                 appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID ;
    557             } else {
    558                 appWidgetId = data.getIntExtra(
    559                         AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
    560             }
    561             if (requestCode == REQUEST_PICK_APPWIDGET && resultCode == Activity.RESULT_OK) {
    562                 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
    563 
    564                 AppWidgetProviderInfo appWidget = null;
    565                 appWidget = appWidgetManager.getAppWidgetInfo(appWidgetId);
    566 
    567                 if (appWidget.configure != null) {
    568                     // Launch over to configure widget, if needed
    569                     Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
    570                     intent.setComponent(appWidget.configure);
    571                     intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    572                     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    573 
    574                     startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
    575                 } else {
    576                     // Otherwise just add it
    577                     onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
    578                 }
    579             } else if (requestCode == REQUEST_CREATE_APPWIDGET && resultCode == Activity.RESULT_OK) {
    580                 mLockPatternUtils.addAppWidget(appWidgetId, 0);
    581                 finishDelayedAndShowLockScreen(appWidgetId);
    582             } else {
    583                 if (mAddingToKeyguard &&
    584                         mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
    585                     int userId = ActivityManager.getCurrentUser();
    586                     AppWidgetHost.deleteAppWidgetIdForSystem(mAppWidgetId, userId);
    587                 }
    588                 finishDelayedAndShowLockScreen(AppWidgetManager.INVALID_APPWIDGET_ID);
    589             }
    590         }
    591     }
    592 
    593     private void finishDelayedAndShowLockScreen(int appWidgetId) {
    594         IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
    595         IWindowManager iWm = IWindowManager.Stub.asInterface(b);
    596         Bundle opts = null;
    597         if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
    598             opts = new Bundle();
    599             opts.putInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET, appWidgetId);
    600         }
    601         try {
    602             iWm.lockNow(opts);
    603         } catch (RemoteException e) {
    604         }
    605 
    606         // Change background to all black
    607         ViewGroup root = (ViewGroup) findViewById(R.id.layout_root);
    608         root.setBackgroundColor(0xFF000000);
    609         // Hide all children
    610         final int childCount = root.getChildCount();
    611         for (int i = 0; i < childCount; i++) {
    612             root.getChildAt(i).setVisibility(View.INVISIBLE);
    613         }
    614         mGridView.postDelayed(new Runnable() {
    615             public void run() {
    616                 finish();
    617             }
    618         }, 500);
    619     }
    620 
    621     void startActivityForResultSafely(Intent intent, int requestCode) {
    622         try {
    623             startActivityForResult(intent, requestCode);
    624         } catch (ActivityNotFoundException e) {
    625             Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
    626         } catch (SecurityException e) {
    627             Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
    628             Log.e(TAG, "Settings does not have the permission to launch " + intent, e);
    629         }
    630     }
    631 }
    632