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