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.datamodel.action; 17 18 import android.content.Context; 19 import android.content.res.Resources; 20 import android.widget.Toast; 21 22 import com.android.messaging.Factory; 23 import com.android.messaging.R; 24 import com.android.messaging.datamodel.DataModel; 25 import com.android.messaging.datamodel.data.MessageData; 26 import com.android.messaging.datamodel.data.ParticipantData; 27 import com.android.messaging.sms.MmsUtils; 28 import com.android.messaging.util.AccessibilityUtil; 29 import com.android.messaging.util.PhoneUtils; 30 import com.android.messaging.util.ThreadUtil; 31 32 import javax.annotation.Nullable; 33 34 /** 35 * Shows one-time, transient notifications in response to action failures (i.e. permanent failures 36 * when sending a message) by showing toasts. 37 */ 38 public class BugleActionToasts { 39 /** 40 * Called when SendMessageAction or DownloadMmsAction finishes 41 * @param conversationId the conversation of the sent or downloaded message 42 * @param success did the action succeed 43 * @param status the message sending status 44 * @param isSms whether the message is sent using SMS 45 * @param subId the subId of the SIM related to this send 46 * @param isSend whether it is a send (false for download) 47 */ onSendMessageOrManualDownloadActionCompleted( final String conversationId, final boolean success, final int status, final boolean isSms, final int subId, final boolean isSend)48 static void onSendMessageOrManualDownloadActionCompleted( 49 final String conversationId, 50 final boolean success, 51 final int status, 52 final boolean isSms, 53 final int subId, 54 final boolean isSend) { 55 // We only show notifications for two cases, i.e. when mobile data is off or when we are 56 // in airplane mode, both of which fail fast with permanent failures. 57 if (!success && status == MmsUtils.MMS_REQUEST_MANUAL_RETRY) { 58 final PhoneUtils phoneUtils = PhoneUtils.get(subId); 59 if (phoneUtils.isAirplaneModeOn()) { 60 if (isSend) { 61 showToast(R.string.send_message_failure_airplane_mode); 62 } else { 63 showToast(R.string.download_message_failure_airplane_mode); 64 } 65 return; 66 } else if (!isSms && !phoneUtils.isMobileDataEnabled()) { 67 if (isSend) { 68 showToast(R.string.send_message_failure_no_data); 69 } else { 70 showToast(R.string.download_message_failure_no_data); 71 } 72 return; 73 } 74 } 75 76 if (AccessibilityUtil.isTouchExplorationEnabled(Factory.get().getApplicationContext())) { 77 final boolean isFocusedConversation = DataModel.get().isFocusedConversation(conversationId); 78 if (isFocusedConversation && success) { 79 // Using View.announceForAccessibility may be preferable, but we do not have a 80 // View, and so we use a toast instead. 81 showToast(isSend ? R.string.send_message_success 82 : R.string.download_message_success); 83 return; 84 } 85 86 // {@link MessageNotificationState#checkFailedMessages} does not post a notification for 87 // failures in observable conversations. For accessibility, we provide an indication 88 // here. 89 final boolean isObservableConversation = DataModel.get().isNewMessageObservable( 90 conversationId); 91 if (isObservableConversation && !success) { 92 showToast(isSend ? R.string.send_message_failure 93 : R.string.download_message_failure); 94 } 95 } 96 } 97 onMessageReceived(final String conversationId, @Nullable final ParticipantData sender, @Nullable final MessageData message)98 public static void onMessageReceived(final String conversationId, 99 @Nullable final ParticipantData sender, @Nullable final MessageData message) { 100 final Context context = Factory.get().getApplicationContext(); 101 if (AccessibilityUtil.isTouchExplorationEnabled(context)) { 102 final boolean isFocusedConversation = DataModel.get().isFocusedConversation( 103 conversationId); 104 if (isFocusedConversation) { 105 final Resources res = context.getResources(); 106 final String senderDisplayName = (sender == null) 107 ? res.getString(R.string.unknown_sender) : sender.getDisplayName(false); 108 final String announcement = res.getString( 109 R.string.incoming_message_announcement, senderDisplayName, 110 (message == null) ? "" : message.getMessageText()); 111 showToast(announcement); 112 } 113 } 114 } 115 onConversationDeleted()116 public static void onConversationDeleted() { 117 showToast(R.string.conversation_deleted); 118 } 119 showToast(final int messageResId)120 private static void showToast(final int messageResId) { 121 ThreadUtil.getMainThreadHandler().post(new Runnable() { 122 @Override 123 public void run() { 124 Toast.makeText(getApplicationContext(), 125 getApplicationContext().getString(messageResId), Toast.LENGTH_LONG).show(); 126 } 127 }); 128 } 129 showToast(final String message)130 private static void showToast(final String message) { 131 ThreadUtil.getMainThreadHandler().post(new Runnable() { 132 @Override 133 public void run() { 134 Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); 135 } 136 }); 137 } 138 getApplicationContext()139 private static Context getApplicationContext() { 140 return Factory.get().getApplicationContext(); 141 } 142 143 private static class UpdateDestinationBlockedActionToast 144 implements UpdateDestinationBlockedAction.UpdateDestinationBlockedActionListener { 145 private final Context mContext; 146 UpdateDestinationBlockedActionToast(final Context context)147 UpdateDestinationBlockedActionToast(final Context context) { 148 mContext = context; 149 } 150 151 @Override onUpdateDestinationBlockedAction( final UpdateDestinationBlockedAction action, final boolean success, final boolean block, final String destination)152 public void onUpdateDestinationBlockedAction( 153 final UpdateDestinationBlockedAction action, 154 final boolean success, 155 final boolean block, 156 final String destination) { 157 if (success) { 158 Toast.makeText(mContext, 159 block 160 ? R.string.update_destination_blocked 161 : R.string.update_destination_unblocked, 162 Toast.LENGTH_LONG 163 ).show(); 164 } 165 } 166 } 167 168 public static UpdateDestinationBlockedAction.UpdateDestinationBlockedActionListener makeUpdateDestinationBlockedActionListener(final Context context)169 makeUpdateDestinationBlockedActionListener(final Context context) { 170 return new UpdateDestinationBlockedActionToast(context); 171 } 172 } 173