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.buildtype.BuildType; 30 import com.android.dialer.common.Assert; 31 import com.android.dialer.common.ConfigProvider; 32 import com.android.dialer.common.ConfigProviderBindings; 33 import com.android.dialer.common.LogUtil; 34 import com.android.dialer.enrichedcall.EnrichedCallCapabilities; 35 import com.android.dialer.enrichedcall.EnrichedCallComponent; 36 import com.android.dialer.enrichedcall.EnrichedCallManager; 37 import com.android.dialer.logging.DialerImpression; 38 import com.android.dialer.logging.Logger; 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_CONNECT_TIME = "post_call_call_connect_time"; 46 private static final String KEY_POST_CALL_CALL_DISCONNECT_TIME = "post_call_call_disconnect_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 promptUserForMessageIfNecessary(Activity activity, View rootView)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 } 59 } 60 } 61 closePrompt()62 public static void closePrompt() { 63 if (activeSnackbar != null && activeSnackbar.isShown()) { 64 activeSnackbar.dismiss(); 65 activeSnackbar = null; 66 } 67 } 68 promptUserToSendMessage(Activity activity, View rootView)69 private static void promptUserToSendMessage(Activity activity, View rootView) { 70 LogUtil.i("PostCall.promptUserToSendMessage", "returned from call, showing post call SnackBar"); 71 String message = activity.getString(R.string.post_call_message); 72 EnrichedCallManager manager = EnrichedCallComponent.get(activity).getEnrichedCallManager(); 73 EnrichedCallCapabilities capabilities = manager.getCapabilities(getPhoneNumber(activity)); 74 LogUtil.i( 75 "PostCall.promptUserToSendMessage", 76 "number: %s, capabilities: %s", 77 LogUtil.sanitizePhoneNumber(getPhoneNumber(activity)), 78 capabilities); 79 80 boolean isRcsPostCall = capabilities != null && capabilities.supportsPostCall(); 81 String actionText = 82 isRcsPostCall 83 ? activity.getString(R.string.post_call_add_message) 84 : activity.getString(R.string.post_call_send_message); 85 86 OnClickListener onClickListener = 87 v -> { 88 Logger.get(activity) 89 .logImpression(DialerImpression.Type.POST_CALL_PROMPT_USER_TO_SEND_MESSAGE_CLICKED); 90 activity.startActivity( 91 PostCallActivity.newIntent(activity, getPhoneNumber(activity), isRcsPostCall)); 92 }; 93 94 int durationMs = 95 (int) ConfigProviderBindings.get(activity).getLong("post_call_prompt_duration_ms", 8_000); 96 activeSnackbar = 97 Snackbar.make(rootView, message, durationMs) 98 .setAction(actionText, onClickListener) 99 .setActionTextColor( 100 activity.getResources().getColor(R.color.dialer_snackbar_action_text_color)); 101 activeSnackbar.show(); 102 Logger.get(activity).logImpression(DialerImpression.Type.POST_CALL_PROMPT_USER_TO_SEND_MESSAGE); 103 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(activity) 104 .edit() 105 .remove(KEY_POST_CALL_CALL_DISCONNECT_TIME) 106 .apply(); 107 } 108 promptUserToViewSentMessage(Activity activity, View rootView)109 private static void promptUserToViewSentMessage(Activity activity, View rootView) { 110 LogUtil.i( 111 "PostCall.promptUserToViewSentMessage", 112 "returned from sending a post call message, message sent."); 113 String message = activity.getString(R.string.post_call_message_sent); 114 String addMessage = activity.getString(R.string.view); 115 OnClickListener onClickListener = 116 v -> { 117 Logger.get(activity) 118 .logImpression( 119 DialerImpression.Type.POST_CALL_PROMPT_USER_TO_VIEW_SENT_MESSAGE_CLICKED); 120 Intent intent = IntentUtil.getSendSmsIntent(getPhoneNumber(activity)); 121 DialerUtils.startActivityWithErrorToast(activity, intent); 122 }; 123 124 activeSnackbar = 125 Snackbar.make(rootView, message, Snackbar.LENGTH_LONG) 126 .setAction(addMessage, onClickListener) 127 .setActionTextColor( 128 activity.getResources().getColor(R.color.dialer_snackbar_action_text_color)) 129 .addCallback( 130 new BaseCallback<Snackbar>() { 131 @Override 132 public void onDismissed(Snackbar snackbar, int i) { 133 super.onDismissed(snackbar, i); 134 clear(snackbar.getContext()); 135 } 136 }); 137 activeSnackbar.show(); 138 Logger.get(activity) 139 .logImpression(DialerImpression.Type.POST_CALL_PROMPT_USER_TO_VIEW_SENT_MESSAGE); 140 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(activity) 141 .edit() 142 .remove(KEY_POST_CALL_MESSAGE_SENT) 143 .apply(); 144 } 145 onCallDisconnected(Context context, String number, long callConnectedMillis)146 public static void onCallDisconnected(Context context, String number, long callConnectedMillis) { 147 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 148 .edit() 149 .putLong(KEY_POST_CALL_CALL_CONNECT_TIME, callConnectedMillis) 150 .putLong(KEY_POST_CALL_CALL_DISCONNECT_TIME, System.currentTimeMillis()) 151 .putString(KEY_POST_CALL_CALL_NUMBER, number) 152 .apply(); 153 } 154 onMessageSent(Context context, String number)155 public static void onMessageSent(Context context, String number) { 156 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 157 .edit() 158 .putString(KEY_POST_CALL_CALL_NUMBER, number) 159 .putBoolean(KEY_POST_CALL_MESSAGE_SENT, true) 160 .apply(); 161 } 162 clear(Context context)163 private static void clear(Context context) { 164 activeSnackbar = null; 165 166 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 167 .edit() 168 .remove(KEY_POST_CALL_CALL_DISCONNECT_TIME) 169 .remove(KEY_POST_CALL_CALL_NUMBER) 170 .remove(KEY_POST_CALL_MESSAGE_SENT) 171 .remove(KEY_POST_CALL_CALL_CONNECT_TIME) 172 .apply(); 173 } 174 shouldPromptUserToSendMessage(Context context)175 private static boolean shouldPromptUserToSendMessage(Context context) { 176 SharedPreferences manager = 177 DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context); 178 long disconnectTimeMillis = manager.getLong(KEY_POST_CALL_CALL_DISCONNECT_TIME, -1); 179 long connectTimeMillis = manager.getLong(KEY_POST_CALL_CALL_CONNECT_TIME, -1); 180 181 long timeSinceDisconnect = System.currentTimeMillis() - disconnectTimeMillis; 182 long callDurationMillis = disconnectTimeMillis - connectTimeMillis; 183 184 ConfigProvider binding = ConfigProviderBindings.get(context); 185 return disconnectTimeMillis != -1 186 && connectTimeMillis != -1 187 && isSimReady(context) 188 && binding.getLong("postcall_last_call_threshold", 30_000) > timeSinceDisconnect 189 && (connectTimeMillis == 0 190 || binding.getLong("postcall_call_duration_threshold", 35_000) > callDurationMillis) 191 && getPhoneNumber(context) != null; 192 } 193 shouldPromptUserToViewSentMessage(Context context)194 private static boolean shouldPromptUserToViewSentMessage(Context context) { 195 return DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 196 .getBoolean(KEY_POST_CALL_MESSAGE_SENT, false); 197 } 198 199 @Nullable getPhoneNumber(Context context)200 private static String getPhoneNumber(Context context) { 201 return DialerUtils.getDefaultSharedPreferenceForDeviceProtectedStorageContext(context) 202 .getString(KEY_POST_CALL_CALL_NUMBER, null); 203 } 204 isEnabled(Context context)205 private static boolean isEnabled(Context context) { 206 @BuildType.Type int type = BuildType.get(); 207 switch (type) { 208 case BuildType.BUGFOOD: 209 case BuildType.DOGFOOD: 210 case BuildType.FISHFOOD: 211 case BuildType.TEST: 212 return ConfigProviderBindings.get(context).getBoolean("enable_post_call", true); 213 case BuildType.RELEASE: 214 return ConfigProviderBindings.get(context).getBoolean("enable_post_call_prod", true); 215 default: 216 Assert.fail(); 217 return false; 218 } 219 } 220 isSimReady(Context context)221 private static boolean isSimReady(Context context) { 222 return context.getSystemService(TelephonyManager.class).getSimState() 223 == TelephonyManager.SIM_STATE_READY; 224 } 225 } 226