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