1 /* 2 * Copyright (C) 2015 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 package com.android.messaging.ui; 17 18 import android.app.Activity; 19 import android.app.Fragment; 20 import android.app.PendingIntent; 21 import android.appwidget.AppWidgetManager; 22 import android.content.ActivityNotFoundException; 23 import android.content.ClipData; 24 import android.content.ComponentName; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.graphics.Point; 29 import android.graphics.Rect; 30 import android.media.RingtoneManager; 31 import android.net.Uri; 32 import android.os.Bundle; 33 import android.provider.ContactsContract.Contacts; 34 import android.provider.ContactsContract.Intents; 35 import android.provider.MediaStore; 36 import android.provider.Telephony; 37 import androidx.annotation.Nullable; 38 import androidx.core.app.TaskStackBuilder; 39 import androidx.localbroadcastmanager.content.LocalBroadcastManager; 40 import android.text.TextUtils; 41 42 import com.android.ex.photo.Intents.PhotoViewIntentBuilder; 43 import com.android.messaging.R; 44 import com.android.messaging.datamodel.ConversationImagePartsView; 45 import com.android.messaging.datamodel.MediaScratchFileProvider; 46 import com.android.messaging.datamodel.MessagingContentProvider; 47 import com.android.messaging.datamodel.data.MessageData; 48 import com.android.messaging.datamodel.data.MessagePartData; 49 import com.android.messaging.datamodel.data.ParticipantData; 50 import com.android.messaging.receiver.NotificationReceiver; 51 import com.android.messaging.sms.MmsSmsUtils; 52 import com.android.messaging.ui.appsettings.ApnEditorActivity; 53 import com.android.messaging.ui.appsettings.ApnSettingsActivity; 54 import com.android.messaging.ui.appsettings.ApplicationSettingsActivity; 55 import com.android.messaging.ui.appsettings.PerSubscriptionSettingsActivity; 56 import com.android.messaging.ui.appsettings.SettingsActivity; 57 import com.android.messaging.ui.attachmentchooser.AttachmentChooserActivity; 58 import com.android.messaging.ui.conversation.ConversationActivity; 59 import com.android.messaging.ui.conversation.LaunchConversationActivity; 60 import com.android.messaging.ui.conversationlist.ArchivedConversationListActivity; 61 import com.android.messaging.ui.conversationlist.ConversationListActivity; 62 import com.android.messaging.ui.conversationlist.ForwardMessageActivity; 63 import com.android.messaging.ui.conversationsettings.PeopleAndOptionsActivity; 64 import com.android.messaging.ui.debug.DebugMmsConfigActivity; 65 import com.android.messaging.ui.photoviewer.BuglePhotoViewActivity; 66 import com.android.messaging.util.Assert; 67 import com.android.messaging.util.ContentType; 68 import com.android.messaging.util.ConversationIdSet; 69 import com.android.messaging.util.LogUtil; 70 import com.android.messaging.util.UiUtils; 71 import com.android.messaging.util.UriUtil; 72 73 /** 74 * A central repository of Intents used to start activities. 75 */ 76 public class UIIntentsImpl extends UIIntents { 77 private static final String CELL_BROADCAST_LIST_ACTIVITY = 78 "com.android.cellbroadcastreceiver.CellBroadcastListActivity"; 79 private static final String CALL_TARGET_CLICK_KEY = "touchPoint"; 80 private static final String CALL_TARGET_CLICK_EXTRA_KEY = 81 "android.telecom.extra.OUTGOING_CALL_EXTRAS"; 82 private static final String MEDIA_SCANNER_CLASS = 83 "com.android.providers.media.MediaScannerService"; 84 private static final String MEDIA_SCANNER_PACKAGE = "com.android.providers.media"; 85 private static final String MEDIA_SCANNER_SCAN_ACTION = "android.media.IMediaScannerService"; 86 87 /** 88 * Get an intent which takes you to a conversation 89 */ getConversationActivityIntent(final Context context, final String conversationId, final MessageData draft, final boolean withCustomTransition)90 private Intent getConversationActivityIntent(final Context context, 91 final String conversationId, final MessageData draft, 92 final boolean withCustomTransition) { 93 final Intent intent = new Intent(context, ConversationActivity.class); 94 95 // Always try to reuse the same ConversationActivity in the current task so that we don't 96 // have two conversation activities in the back stack. 97 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 98 99 // Otherwise we're starting a new conversation 100 if (conversationId != null) { 101 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_ID, conversationId); 102 } 103 if (draft != null) { 104 intent.putExtra(UI_INTENT_EXTRA_DRAFT_DATA, draft); 105 106 // If draft attachments came from an external content provider via a share intent, we 107 // need to propagate the URI permissions through to ConversationActivity. This requires 108 // putting the URIs into the ClipData (setData also works, but accepts only one URI). 109 ClipData clipData = null; 110 for (final MessagePartData partData : draft.getParts()) { 111 if (partData.isAttachment()) { 112 final Uri uri = partData.getContentUri(); 113 if (clipData == null) { 114 clipData = ClipData.newRawUri("Attachments", uri); 115 } else { 116 clipData.addItem(new ClipData.Item(uri)); 117 } 118 } 119 } 120 if (clipData != null) { 121 intent.setClipData(clipData); 122 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 123 } 124 } 125 if (withCustomTransition) { 126 intent.putExtra(UI_INTENT_EXTRA_WITH_CUSTOM_TRANSITION, true); 127 } 128 129 if (!(context instanceof Activity)) { 130 // If the caller supplies an application context, and not an activity context, we must 131 // include this flag 132 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 133 } 134 return intent; 135 } 136 137 @Override launchPermissionCheckActivity(final Context context)138 public void launchPermissionCheckActivity(final Context context) { 139 final Intent intent = new Intent(context, PermissionCheckActivity.class); 140 context.startActivity(intent); 141 } 142 143 /** 144 * Get an intent which takes you to the conversation list 145 */ getConversationListActivityIntent(final Context context)146 private Intent getConversationListActivityIntent(final Context context) { 147 return new Intent(context, ConversationListActivity.class); 148 } 149 150 @Override launchConversationListActivity(final Context context)151 public void launchConversationListActivity(final Context context) { 152 final Intent intent = getConversationListActivityIntent(context); 153 context.startActivity(intent); 154 } 155 156 /** 157 * Get an intent which shows the low storage warning activity. 158 */ getSmsStorageLowWarningActivityIntent(final Context context)159 private Intent getSmsStorageLowWarningActivityIntent(final Context context) { 160 return new Intent(context, SmsStorageLowWarningActivity.class); 161 } 162 163 @Override launchConversationActivity(final Context context, final String conversationId, final MessageData draft, final Bundle activityOptions, final boolean withCustomTransition)164 public void launchConversationActivity(final Context context, 165 final String conversationId, final MessageData draft, final Bundle activityOptions, 166 final boolean withCustomTransition) { 167 Assert.isTrue(!withCustomTransition || activityOptions != null); 168 final Intent intent = getConversationActivityIntent(context, conversationId, draft, 169 withCustomTransition); 170 context.startActivity(intent, activityOptions); 171 } 172 173 @Override launchConversationActivityNewTask( final Context context, final String conversationId)174 public void launchConversationActivityNewTask( 175 final Context context, final String conversationId) { 176 final Intent intent = getConversationActivityIntent(context, conversationId, null, 177 false /* withCustomTransition */); 178 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 179 context.startActivity(intent); 180 } 181 182 @Override launchConversationActivityWithParentStack(final Context context, final String conversationId, final String smsBody)183 public void launchConversationActivityWithParentStack(final Context context, 184 final String conversationId, final String smsBody) { 185 final MessageData messageData = TextUtils.isEmpty(smsBody) 186 ? null 187 : MessageData.createDraftSmsMessage(conversationId, null, smsBody); 188 TaskStackBuilder.create(context) 189 .addNextIntentWithParentStack( 190 getConversationActivityIntent(context, conversationId, messageData, 191 false /* withCustomTransition */)) 192 .startActivities(); 193 } 194 195 @Override launchCreateNewConversationActivity(final Context context, final MessageData draft)196 public void launchCreateNewConversationActivity(final Context context, 197 final MessageData draft) { 198 final Intent intent = getConversationActivityIntent(context, null, draft, 199 false /* withCustomTransition */); 200 context.startActivity(intent); 201 } 202 203 @Override launchDebugMmsConfigActivity(final Context context)204 public void launchDebugMmsConfigActivity(final Context context) { 205 context.startActivity(new Intent(context, DebugMmsConfigActivity.class)); 206 } 207 208 @Override launchAddContactActivity(final Context context, final String destination)209 public void launchAddContactActivity(final Context context, final String destination) { 210 final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); 211 final String destinationType = MmsSmsUtils.isEmailAddress(destination) ? 212 Intents.Insert.EMAIL : Intents.Insert.PHONE; 213 intent.setType(Contacts.CONTENT_ITEM_TYPE); 214 intent.putExtra(destinationType, destination); 215 startExternalActivity(context, intent); 216 } 217 218 @Override launchSettingsActivity(final Context context)219 public void launchSettingsActivity(final Context context) { 220 final Intent intent = new Intent(context, SettingsActivity.class); 221 context.startActivity(intent); 222 } 223 224 @Override launchArchivedConversationsActivity(final Context context)225 public void launchArchivedConversationsActivity(final Context context) { 226 final Intent intent = new Intent(context, ArchivedConversationListActivity.class); 227 context.startActivity(intent); 228 } 229 230 @Override launchBlockedParticipantsActivity(final Context context)231 public void launchBlockedParticipantsActivity(final Context context) { 232 final Intent intent = new Intent(context, BlockedParticipantsActivity.class); 233 context.startActivity(intent); 234 } 235 236 @Override launchDocumentImagePicker(final Fragment fragment)237 public void launchDocumentImagePicker(final Fragment fragment) { 238 final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 239 intent.putExtra(Intent.EXTRA_MIME_TYPES, MessagePartData.ACCEPTABLE_GALLERY_MEDIA_TYPES); 240 intent.addCategory(Intent.CATEGORY_OPENABLE); 241 intent.setType(ContentType.ANY_TYPE); 242 243 fragment.startActivityForResult(intent, REQUEST_PICK_MEDIA_FROM_DOCUMENT_PICKER); 244 } 245 246 @Override launchContactCardPicker(final Fragment fragment)247 public void launchContactCardPicker(final Fragment fragment) { 248 final Intent intent = new Intent(Intent.ACTION_PICK); 249 intent.setType(Contacts.CONTENT_TYPE); 250 251 try { 252 fragment.startActivityForResult(intent, REQUEST_PICK_CONTACT_CARD); 253 } catch (final ActivityNotFoundException ex) { 254 LogUtil.w(LogUtil.BUGLE_TAG, "Couldn't find activity:", ex); 255 UiUtils.showToastAtBottom(R.string.activity_not_found_message); 256 } 257 } 258 259 @Override launchPeopleAndOptionsActivity(final Activity activity, final String conversationId)260 public void launchPeopleAndOptionsActivity(final Activity activity, 261 final String conversationId) { 262 final Intent intent = new Intent(activity, PeopleAndOptionsActivity.class); 263 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_ID, conversationId); 264 activity.startActivityForResult(intent, 0); 265 } 266 267 @Override launchPhoneCallActivity(final Context context, final String phoneNumber, final Point clickPosition)268 public void launchPhoneCallActivity(final Context context, final String phoneNumber, 269 final Point clickPosition) { 270 final Intent intent = new Intent(Intent.ACTION_CALL, 271 Uri.parse(UriUtil.SCHEME_TEL + phoneNumber)); 272 final Bundle extras = new Bundle(); 273 extras.putParcelable(CALL_TARGET_CLICK_KEY, clickPosition); 274 intent.putExtra(CALL_TARGET_CLICK_EXTRA_KEY, extras); 275 startExternalActivity(context, intent); 276 } 277 278 @Override launchClassZeroActivity(final Context context, final ContentValues messageValues)279 public void launchClassZeroActivity(final Context context, final ContentValues messageValues) { 280 final Intent classZeroIntent = new Intent(context, ClassZeroActivity.class) 281 .putExtra(UI_INTENT_EXTRA_MESSAGE_VALUES, messageValues) 282 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); 283 context.startActivity(classZeroIntent); 284 } 285 286 @Override launchForwardMessageActivity(final Context context, final MessageData message)287 public void launchForwardMessageActivity(final Context context, final MessageData message) { 288 final Intent forwardMessageIntent = new Intent(context, ForwardMessageActivity.class) 289 .putExtra(UI_INTENT_EXTRA_DRAFT_DATA, message); 290 context.startActivity(forwardMessageIntent); 291 } 292 293 @Override launchVCardDetailActivity(final Context context, final Uri vcardUri)294 public void launchVCardDetailActivity(final Context context, final Uri vcardUri) { 295 final Intent vcardDetailIntent = new Intent(context, VCardDetailActivity.class) 296 .putExtra(UI_INTENT_EXTRA_VCARD_URI, vcardUri); 297 context.startActivity(vcardDetailIntent); 298 } 299 300 @Override launchSaveVCardToContactsActivity(final Context context, final Uri vcardUri)301 public void launchSaveVCardToContactsActivity(final Context context, final Uri vcardUri) { 302 Assert.isTrue(MediaScratchFileProvider.isMediaScratchSpaceUri(vcardUri)); 303 final Intent intent = new Intent(); 304 intent.setAction(Intent.ACTION_VIEW); 305 intent.setDataAndType(vcardUri, ContentType.TEXT_VCARD.toLowerCase()); 306 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 307 startExternalActivity(context, intent); 308 } 309 310 @Override launchAttachmentChooserActivity(final Activity activity, final String conversationId, final int requestCode)311 public void launchAttachmentChooserActivity(final Activity activity, 312 final String conversationId, final int requestCode) { 313 final Intent intent = new Intent(activity, AttachmentChooserActivity.class); 314 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_ID, conversationId); 315 activity.startActivityForResult(intent, requestCode); 316 } 317 318 @Override launchFullScreenVideoViewer(final Context context, final Uri videoUri)319 public void launchFullScreenVideoViewer(final Context context, final Uri videoUri) { 320 final Intent intent = new Intent(Intent.ACTION_VIEW); 321 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 322 323 // So we don't see "surrounding" images in Gallery 324 intent.putExtra("SingleItemOnly", true); 325 intent.setDataAndType(videoUri, ContentType.VIDEO_UNSPECIFIED); 326 startExternalActivity(context, intent); 327 } 328 329 @Override launchFullScreenPhotoViewer(final Activity activity, final Uri initialPhoto, final Rect initialPhotoBounds, final Uri photosUri)330 public void launchFullScreenPhotoViewer(final Activity activity, final Uri initialPhoto, 331 final Rect initialPhotoBounds, final Uri photosUri) { 332 final PhotoViewIntentBuilder builder = 333 com.android.ex.photo.Intents.newPhotoViewIntentBuilder( 334 activity, BuglePhotoViewActivity.class); 335 builder.setPhotosUri(photosUri.toString()); 336 builder.setInitialPhotoUri(initialPhoto.toString()); 337 builder.setProjection(ConversationImagePartsView.PhotoViewQuery.PROJECTION); 338 339 // Set the location of the imageView so that the photoviewer can animate from that location 340 // to full screen. 341 builder.setScaleAnimation(initialPhotoBounds.left, initialPhotoBounds.top, 342 initialPhotoBounds.width(), initialPhotoBounds.height()); 343 344 builder.setDisplayThumbsFullScreen(false); 345 builder.setMaxInitialScale(8); 346 activity.startActivity(builder.build()); 347 activity.overridePendingTransition(0, 0); 348 } 349 350 @Override launchApplicationSettingsActivity(final Context context, final boolean topLevel)351 public void launchApplicationSettingsActivity(final Context context, final boolean topLevel) { 352 final Intent intent = new Intent(context, ApplicationSettingsActivity.class); 353 intent.putExtra(UI_INTENT_EXTRA_TOP_LEVEL_SETTINGS, topLevel); 354 context.startActivity(intent); 355 } 356 357 @Override launchPerSubscriptionSettingsActivity(final Context context, final int subId, final String settingTitle)358 public void launchPerSubscriptionSettingsActivity(final Context context, final int subId, 359 final String settingTitle) { 360 final Intent intent = getPerSubscriptionSettingsIntent(context, subId, settingTitle); 361 context.startActivity(intent); 362 } 363 364 @Override getViewUrlIntent(final String url)365 public Intent getViewUrlIntent(final String url) { 366 final Uri uri = Uri.parse(url); 367 return new Intent(Intent.ACTION_VIEW, uri); 368 } 369 370 @Override broadcastConversationSelfIdChange(final Context context, final String conversationId, final String conversationSelfId)371 public void broadcastConversationSelfIdChange(final Context context, 372 final String conversationId, final String conversationSelfId) { 373 final Intent intent = new Intent(CONVERSATION_SELF_ID_CHANGE_BROADCAST_ACTION); 374 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_ID, conversationId); 375 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_SELF_ID, conversationSelfId); 376 LocalBroadcastManager.getInstance(context).sendBroadcast(intent); 377 } 378 379 @Override getPendingIntentForConversationListActivity(final Context context)380 public PendingIntent getPendingIntentForConversationListActivity(final Context context) { 381 final Intent intent = getConversationListActivityIntent(context); 382 return getPendingIntentWithParentStack(context, intent, 0); 383 } 384 385 @Override getPendingIntentForConversationActivity(final Context context, final String conversationId, final MessageData draft)386 public PendingIntent getPendingIntentForConversationActivity(final Context context, 387 final String conversationId, final MessageData draft) { 388 final Intent intent = getConversationActivityIntent(context, conversationId, draft, 389 false /* withCustomTransition */); 390 // Ensure that the platform doesn't reuse PendingIntents across conversations 391 intent.setData(MessagingContentProvider.buildConversationMetadataUri(conversationId)); 392 return getPendingIntentWithParentStack(context, intent, 0); 393 } 394 395 @Override getIntentForConversationActivity(final Context context, final String conversationId, final MessageData draft)396 public Intent getIntentForConversationActivity(final Context context, 397 final String conversationId, final MessageData draft) { 398 final Intent intent = getConversationActivityIntent(context, conversationId, draft, 399 false /* withCustomTransition */); 400 return intent; 401 } 402 403 @Override getPendingIntentForSendingMessageToConversation(final Context context, final String conversationId, final String selfId, final boolean requiresMms, final int requestCode)404 public PendingIntent getPendingIntentForSendingMessageToConversation(final Context context, 405 final String conversationId, final String selfId, final boolean requiresMms, 406 final int requestCode) { 407 final Intent intent = new Intent(context, RemoteInputEntrypointActivity.class); 408 intent.setAction(Intent.ACTION_SENDTO); 409 // Ensure that the platform doesn't reuse PendingIntents across conversations 410 intent.setData(MessagingContentProvider.buildConversationMetadataUri(conversationId)); 411 intent.putExtra(UIIntents.UI_INTENT_EXTRA_CONVERSATION_ID, conversationId); 412 intent.putExtra(UIIntents.UI_INTENT_EXTRA_SELF_ID, selfId); 413 intent.putExtra(UIIntents.UI_INTENT_EXTRA_REQUIRES_MMS, requiresMms); 414 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 415 return getPendingIntentWithParentStack(context, intent, requestCode); 416 } 417 418 @Override getPendingIntentForClearingNotifications(final Context context, final int updateTargets, final ConversationIdSet conversationIdSet, final int requestCode)419 public PendingIntent getPendingIntentForClearingNotifications(final Context context, 420 final int updateTargets, final ConversationIdSet conversationIdSet, 421 final int requestCode) { 422 final Intent intent = new Intent(context, NotificationReceiver.class); 423 intent.setAction(ACTION_RESET_NOTIFICATIONS); 424 intent.putExtra(UI_INTENT_EXTRA_NOTIFICATIONS_UPDATE, updateTargets); 425 if (conversationIdSet != null) { 426 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_ID_SET, 427 conversationIdSet.getDelimitedString()); 428 } 429 return PendingIntent.getBroadcast(context, 430 requestCode, intent, 431 PendingIntent.FLAG_UPDATE_CURRENT); 432 } 433 434 /** 435 * Gets a PendingIntent associated with an Intent to start an Activity. All notifications 436 * that starts an Activity must use this method to get a PendingIntent, which achieves two 437 * goals: 438 * 1. The target activities will be created, with any existing ones destroyed. This ensures 439 * we don't end up with multiple instances of ConversationListActivity, for example. 440 * 2. The target activity, when launched, will have its backstack correctly constructed so 441 * back navigation will work correctly. 442 */ getPendingIntentWithParentStack(final Context context, final Intent intent, final int requestCode)443 private static PendingIntent getPendingIntentWithParentStack(final Context context, 444 final Intent intent, final int requestCode) { 445 final TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); 446 // Adds the back stack for the Intent (plus the Intent itself) 447 stackBuilder.addNextIntentWithParentStack(intent); 448 final PendingIntent resultPendingIntent = 449 stackBuilder.getPendingIntent(requestCode, PendingIntent.FLAG_UPDATE_CURRENT); 450 return resultPendingIntent; 451 } 452 453 @Override getRingtonePickerIntent(final String title, final Uri existingUri, final Uri defaultUri, final int toneType)454 public Intent getRingtonePickerIntent(final String title, final Uri existingUri, 455 final Uri defaultUri, final int toneType) { 456 return new Intent(RingtoneManager.ACTION_RINGTONE_PICKER) 457 .putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, toneType) 458 .putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, title) 459 .putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existingUri) 460 .putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, defaultUri); 461 } 462 463 @Override getPendingIntentForLowStorageNotifications(final Context context)464 public PendingIntent getPendingIntentForLowStorageNotifications(final Context context) { 465 final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); 466 final Intent conversationListIntent = getConversationListActivityIntent(context); 467 taskStackBuilder.addNextIntent(conversationListIntent); 468 taskStackBuilder.addNextIntentWithParentStack( 469 getSmsStorageLowWarningActivityIntent(context)); 470 471 return taskStackBuilder.getPendingIntent( 472 0, PendingIntent.FLAG_UPDATE_CURRENT); 473 } 474 475 @Override getPendingIntentForSecondaryUserNewMessageNotification( final Context context)476 public PendingIntent getPendingIntentForSecondaryUserNewMessageNotification( 477 final Context context) { 478 return getPendingIntentForConversationListActivity(context); 479 } 480 481 @Override getWirelessAlertsIntent()482 public Intent getWirelessAlertsIntent() { 483 final Intent intent = new Intent(Intent.ACTION_MAIN); 484 intent.setComponent(new ComponentName(CMAS_COMPONENT, CELL_BROADCAST_LIST_ACTIVITY)); 485 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 486 return intent; 487 } 488 489 @Override getApnEditorIntent(final Context context, final String rowId, final int subId)490 public Intent getApnEditorIntent(final Context context, final String rowId, final int subId) { 491 final Intent intent = new Intent(context, ApnEditorActivity.class); 492 intent.putExtra(UI_INTENT_EXTRA_APN_ROW_ID, rowId); 493 intent.putExtra(UI_INTENT_EXTRA_SUB_ID, subId); 494 return intent; 495 } 496 497 @Override getApnSettingsIntent(final Context context, final int subId)498 public Intent getApnSettingsIntent(final Context context, final int subId) { 499 final Intent intent = new Intent(context, ApnSettingsActivity.class) 500 .putExtra(UI_INTENT_EXTRA_SUB_ID, subId); 501 return intent; 502 } 503 504 @Override getAdvancedSettingsIntent(final Context context)505 public Intent getAdvancedSettingsIntent(final Context context) { 506 return getPerSubscriptionSettingsIntent(context, ParticipantData.DEFAULT_SELF_SUB_ID, null); 507 } 508 509 @Override getChangeDefaultSmsAppIntent(final Activity activity)510 public Intent getChangeDefaultSmsAppIntent(final Activity activity) { 511 final Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT); 512 intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, activity.getPackageName()); 513 return intent; 514 } 515 516 @Override launchBrowserForUrl(final Context context, final String url)517 public void launchBrowserForUrl(final Context context, final String url) { 518 final Intent intent = getViewUrlIntent(url); 519 startExternalActivity(context, intent); 520 } 521 522 /** 523 * Provides a safe way to handle external activities which may not exist. 524 */ startExternalActivity(final Context context, final Intent intent)525 private void startExternalActivity(final Context context, final Intent intent) { 526 try { 527 context.startActivity(intent); 528 } catch (final ActivityNotFoundException ex) { 529 LogUtil.w(LogUtil.BUGLE_TAG, "Couldn't find activity:", ex); 530 UiUtils.showToastAtBottom(R.string.activity_not_found_message); 531 } 532 } 533 getPerSubscriptionSettingsIntent(final Context context, final int subId, @Nullable final String settingTitle)534 private Intent getPerSubscriptionSettingsIntent(final Context context, final int subId, 535 @Nullable final String settingTitle) { 536 return new Intent(context, PerSubscriptionSettingsActivity.class) 537 .putExtra(UI_INTENT_EXTRA_SUB_ID, subId) 538 .putExtra(UI_INTENT_EXTRA_PER_SUBSCRIPTION_SETTING_TITLE, settingTitle); 539 } 540 541 @Override getLaunchConversationActivityIntent(final Context context)542 public Intent getLaunchConversationActivityIntent(final Context context) { 543 final Intent intent = new Intent(context, LaunchConversationActivity.class); 544 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY); 545 return intent; 546 } 547 548 @Override kickMediaScanner(final Context context, final String volume)549 public void kickMediaScanner(final Context context, final String volume) { 550 final Intent intent = new Intent(MEDIA_SCANNER_SCAN_ACTION) 551 .putExtra(MediaStore.MEDIA_SCANNER_VOLUME, volume) 552 .setClassName(MEDIA_SCANNER_PACKAGE, MEDIA_SCANNER_CLASS); 553 context.startService(intent); 554 } 555 556 @Override getWidgetPendingIntentForConversationActivity(final Context context, final String conversationId, final int requestCode)557 public PendingIntent getWidgetPendingIntentForConversationActivity(final Context context, 558 final String conversationId, final int requestCode) { 559 final Intent intent = getConversationActivityIntent(context, null, null, 560 false /* withCustomTransition */); 561 if (conversationId != null) { 562 intent.putExtra(UI_INTENT_EXTRA_CONVERSATION_ID, conversationId); 563 564 // Set the action to something unique to this conversation so if someone calls this 565 // function again on a different conversation, they'll get a new PendingIntent instead 566 // of the old one. 567 intent.setAction(ACTION_WIDGET_CONVERSATION + conversationId); 568 } 569 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 570 return getPendingIntentWithParentStack(context, intent, requestCode); 571 } 572 573 @Override getWidgetPendingIntentForConversationListActivity( final Context context)574 public PendingIntent getWidgetPendingIntentForConversationListActivity( 575 final Context context) { 576 final Intent intent = getConversationListActivityIntent(context); 577 return getPendingIntentWithParentStack(context, intent, 0); 578 } 579 580 @Override getWidgetPendingIntentForConfigurationActivity(final Context context, final int appWidgetId)581 public PendingIntent getWidgetPendingIntentForConfigurationActivity(final Context context, 582 final int appWidgetId) { 583 final Intent configureIntent = new Intent(context, WidgetPickConversationActivity.class); 584 configureIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 585 configureIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); 586 configureIntent.setData(Uri.parse(configureIntent.toUri(Intent.URI_INTENT_SCHEME))); 587 configureIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY); 588 return getPendingIntentWithParentStack(context, configureIntent, 0); 589 } 590 } 591