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 onCreate(Bundle savedInstanceState)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 */ setResultData(int code, Intent intent)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 */ Item(Context context, CharSequence label)158 Item(Context context, CharSequence label) { 159 this.label = label; 160 mContext = context; 161 } 162 loadWidgetPreview(ImageView v)163 void loadWidgetPreview(ImageView v) { 164 mWidgetPreviewLoader = new WidgetPreviewLoader(mContext, v); 165 mWidgetPreviewLoader.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null); 166 } 167 cancelLoadingWidgetPreview()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 */ getIntent()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 getLabel()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; WidgetPreviewLoader(Context context, ImageView v)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 } doInBackground(Void... params)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 } onProgressUpdate(Bitmap... values)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; WeakReferenceThreadLocal()235 public WeakReferenceThreadLocal() { 236 mThreadLocal = new ThreadLocal<WeakReference<T>>(); 237 } 238 initialValue()239 abstract T initialValue(); 240 set(T t)241 public void set(T t) { 242 mThreadLocal.set(new WeakReference<T>(t)); 243 } 244 get()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 initialValue()265 protected Canvas initialValue() { 266 return new Canvas(); 267 } 268 } 269 270 class PaintCache extends WeakReferenceThreadLocal<Paint> { 271 @Override initialValue()272 protected Paint initialValue() { 273 return null; 274 } 275 } 276 277 class BitmapCache extends WeakReferenceThreadLocal<Bitmap> { 278 @Override initialValue()279 protected Bitmap initialValue() { 280 return null; 281 } 282 } 283 284 class RectCache extends WeakReferenceThreadLocal<Rect> { 285 @Override initialValue()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 getWidgetPreview(ComponentName provider, int previewImage, int iconId, int maxWidth, int maxHeight)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 } getFullResDefaultActivityIcon()380 public Drawable getFullResDefaultActivityIcon() { 381 return getFullResIcon(Resources.getSystem(), 382 android.R.mipmap.sym_def_app_icon); 383 } 384 getFullResIcon(Resources resources, int iconId)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 getFullResIcon(String packageName, int iconId)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 renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h)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 renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h, float scale)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 createItem(Context context, AppWidgetProviderInfo info, Bundle extras)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 */ AppWidgetAdapter(Context context, List<Item> items)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 */ getCount()458 public int getCount() { 459 return mItems.size(); 460 } 461 462 /** 463 * {@inheritDoc} 464 */ getItem(int position)465 public Object getItem(int position) { 466 return mItems.get(position); 467 } 468 469 /** 470 * {@inheritDoc} 471 */ getItemId(int position)472 public long getItemId(int position) { 473 return position; 474 } 475 476 /** 477 * {@inheritDoc} 478 */ getView(int position, View convertView, ViewGroup parent)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 cancelAllWidgetPreviewLoaders()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 onItemClick(AdapterView<?> parent, View view, int position, long id)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 onDestroy()543 protected void onDestroy() { 544 if (mAppWidgetAdapter != null) { 545 mAppWidgetAdapter.cancelAllWidgetPreviewLoaders(); 546 } 547 super.onDestroy(); 548 } 549 550 @Override onActivityResult(int requestCode, int resultCode, Intent data)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 finishDelayedAndShowLockScreen(int appWidgetId)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 startActivityForResultSafely(Intent intent, int requestCode)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