1 /* 2 * Copyright (C) 2017 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.dialer.postcall; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.SharedPreferences; 23 import android.support.annotation.Nullable; 24 import android.support.design.widget.BaseTransientBottomBar.BaseCallback; 25 import android.support.design.widget.Snackbar; 26 import android.telephony.TelephonyManager; 27 import android.view.View; 28 import android.view.View.OnClickListener; 29 import com.android.dialer.common.Assert; 30 import com.android.dialer.common.LogUtil; 31 import com.android.dialer.configprovider.ConfigProvider; 32 import com.android.dialer.configprovider.ConfigProviderBindings; 33 import com.android.dialer.enrichedcall.EnrichedCallCapabilities; 34 import com.android.dialer.enrichedcall.EnrichedCallComponent; 35 import com.android.dialer.enrichedcall.EnrichedCallManager; 36 import com.android.dialer.logging.DialerImpression; 37 import com.android.dialer.logging.Logger; 38 import com.android.dialer.performancereport.PerformanceReport; 39 import com.android.dialer.util.DialerUtils; 40 import com.android.dialer.util.IntentUtil; 41 42 /** Helper class to handle all post call actions. */ 43 public class PostCall { 44 45 private static final String KEY_POST_CALL_CALL_DISCONNECT_TIME = "post_call_call_disconnect_time"; 46 private static final String KEY_POST_CALL_CALL_CONNECT_TIME = "post_call_call_connect_time"; 47 private static final String KEY_POST_CALL_CALL_NUMBER = "post_call_call_number"; 48 private static final String KEY_POST_CALL_MESSAGE_SENT = "post_call_message_sent"; 49 50 private static Snackbar activeSnackbar; 51 52 public static void promptUserForMessageIfNecessary(Activity activity, View rootView) { 53 if (isEnabled(activity)) { 54 if (shouldPromptUserToViewSentMessage(activity)) { 55 promptUserToViewSentMessage(activity, rootView); 56 } else if (shouldPromptUserToSendMessage(activity)) { 57 promptUserToSendMessage(activity, rootView); 58 } else { 59 clear(activity); 60 } 61 } 62 } 63 64 public static void closePrompt() { 65 if (activeSnackbar != null && activeSnackbar.isShown()) { 66 activeSnackbar.dismiss(); 67 activeSnackbar = null; 68 } 69 } 70 71 private static void promptUserToSendMessage(Activity activity, View rootView) { 72 LogUtil.i("PostCall.promptUserToSendMessage", "returned from call, showing post call SnackBar"); 73 String message = activity.getString(R.string.post_call_message); 74 EnrichedCallManager manager = EnrichedCallComponent.get(activity).getEnrichedCallManager(); 75 EnrichedCallCapabilities capabilities = manager.getCapabilities(getPhoneNumber(activity)); 76 LogUtil.i( 77 "PostCall.promptUserToSendMessage", 78 "number: %s, capabilities: %s", 79 LogUtil.sanitizePhoneNumber(getPhoneNumber(activity)), 80 capabilities); 81 82 boolean isRcsPostCall = capabilities != null && capabilities.supportsPostCall(); 83 String actionText = 84 isRcsPostCall 85 ? activity.getString(R.string.post_call_add_message) 86 : activity.getString(R.string.post_call_send_message); 87 88 String number = Assert.isNotNull(getPhoneNumber(activity)); 89 OnClickListener onClickListener = 90 v -> { 91 Logger.get(activity) 92 .logImpression(DialerImpression.Type.POST_CALL_PROMPT_USER_TO_SEND_MESSAGE_CLICKED); 93 activity.startActivity(PostCallActivity.newIntent(activity, number, isRcsPostCall)); 94 }; 95 96 int durationMs = 97 (int) ConfigProviderBindings.get(activity).getLong("post_call_prompt_duration_ms", 8_000); 98 activeSnackbar = 99 Snackbar.make(rootView, message, durationMs) 100 .setAction(actionText, onClickListener) 101 .setActionTextColor( 102 activity.getResources().getColor(R.color.dialer_snackbar_action_text_color)); 103 activeSnackbar.show(); 104 Logger.get(activity).logImpression(DialerImpression.Type.POST_CALL_PROMPT_USER_TO_SEND_MESSAGE); 105 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(activity) 106 .edit() 107 .remove(KEY_POST_CALL_CALL_DISCONNECT_TIME) 108 .apply(); 109 } 110 111 private static void promptUserToViewSentMessage(Activity activity, View rootView) { 112 LogUtil.i( 113 "PostCall.promptUserToViewSentMessage", 114 "returned from sending a post call message, message sent."); 115 String message = activity.getString(R.string.post_call_message_sent); 116 String addMessage = activity.getString(R.string.view); 117 String number = Assert.isNotNull(getPhoneNumber(activity)); 118 OnClickListener onClickListener = 119 v -> { 120 Logger.get(activity) 121 .logImpression( 122 DialerImpression.Type.POST_CALL_PROMPT_USER_TO_VIEW_SENT_MESSAGE_CLICKED); 123 Intent intent = IntentUtil.getSendSmsIntent(number); 124 DialerUtils.startActivityWithErrorToast(activity, intent); 125 }; 126 127 activeSnackbar = 128 Snackbar.make(rootView, message, Snackbar.LENGTH_LONG) 129 .setAction(addMessage, onClickListener) 130 .setActionTextColor( 131 activity.getResources().getColor(R.color.dialer_snackbar_action_text_color)) 132 .addCallback( 133 new BaseCallback<Snackbar>() { 134 @Override 135 public void onDismissed(Snackbar snackbar, int i) { 136 super.onDismissed(snackbar, i); 137 clear(snackbar.getContext()); 138 } 139 }); 140 activeSnackbar.show(); 141 Logger.get(activity) 142 .logImpression(DialerImpression.Type.POST_CALL_PROMPT_USER_TO_VIEW_SENT_MESSAGE); 143 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(activity) 144 .edit() 145 .remove(KEY_POST_CALL_MESSAGE_SENT) 146 .apply(); 147 } 148 149 public static void onCallDisconnected(Context context, String number, long callConnectedMillis) { 150 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 151 .edit() 152 .putLong(KEY_POST_CALL_CALL_CONNECT_TIME, callConnectedMillis) 153 .putLong(KEY_POST_CALL_CALL_DISCONNECT_TIME, System.currentTimeMillis()) 154 .putString(KEY_POST_CALL_CALL_NUMBER, number) 155 .apply(); 156 } 157 158 public static void onMessageSent(Context context, String number) { 159 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 160 .edit() 161 .putString(KEY_POST_CALL_CALL_NUMBER, number) 162 .putBoolean(KEY_POST_CALL_MESSAGE_SENT, true) 163 .apply(); 164 } 165 166 /** 167 * Restart performance recording if there is a recent call (disconnect time to now is under 168 * threshold) 169 */ 170 public static void restartPerformanceRecordingIfARecentCallExist(Context context) { 171 long disconnectTimeMillis = 172 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 173 .getLong(PostCall.KEY_POST_CALL_CALL_DISCONNECT_TIME, -1); 174 if (disconnectTimeMillis != -1 && PerformanceReport.isRecording()) { 175 PerformanceReport.startRecording(); 176 } 177 } 178 179 private static void clear(Context context) { 180 activeSnackbar = null; 181 182 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 183 .edit() 184 .remove(KEY_POST_CALL_CALL_DISCONNECT_TIME) 185 .remove(KEY_POST_CALL_CALL_NUMBER) 186 .remove(KEY_POST_CALL_MESSAGE_SENT) 187 .remove(KEY_POST_CALL_CALL_CONNECT_TIME) 188 .apply(); 189 } 190 191 private static boolean shouldPromptUserToSendMessage(Context context) { 192 SharedPreferences manager = 193 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context); 194 long disconnectTimeMillis = manager.getLong(KEY_POST_CALL_CALL_DISCONNECT_TIME, -1); 195 long connectTimeMillis = manager.getLong(KEY_POST_CALL_CALL_CONNECT_TIME, -1); 196 197 long timeSinceDisconnect = System.currentTimeMillis() - disconnectTimeMillis; 198 long callDurationMillis = disconnectTimeMillis - connectTimeMillis; 199 200 ConfigProvider binding = ConfigProviderBindings.get(context); 201 return disconnectTimeMillis != -1 202 && connectTimeMillis != -1 203 && isSimReady(context) 204 && binding.getLong("postcall_last_call_threshold", 30_000) > timeSinceDisconnect 205 && (connectTimeMillis == 0 206 || binding.getLong("postcall_call_duration_threshold", 35_000) > callDurationMillis) 207 && getPhoneNumber(context) != null; 208 } 209 210 private static boolean shouldPromptUserToViewSentMessage(Context context) { 211 return DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 212 .getBoolean(KEY_POST_CALL_MESSAGE_SENT, false); 213 } 214 215 @Nullable 216 private static String getPhoneNumber(Context context) { 217 return DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 218 .getString(KEY_POST_CALL_CALL_NUMBER, null); 219 } 220 221 private static boolean isEnabled(Context context) { 222 return ConfigProviderBindings.get(context).getBoolean("enable_post_call_prod", true); 223 } 224 225 private static boolean isSimReady(Context context) { 226 return context.getSystemService(TelephonyManager.class).getSimState() 227 == TelephonyManager.SIM_STATE_READY; 228 } 229 } 230