• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.callintent;
18 
19 import android.content.Intent;
20 import android.net.Uri;
21 import android.os.Bundle;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.os.SystemClock;
25 import android.support.annotation.NonNull;
26 import android.support.annotation.Nullable;
27 import android.support.annotation.VisibleForTesting;
28 import android.telecom.PhoneAccount;
29 import android.telecom.PhoneAccountHandle;
30 import android.telecom.TelecomManager;
31 import android.telecom.VideoProfile;
32 import android.text.TextUtils;
33 import com.android.dialer.common.Assert;
34 import com.android.dialer.performancereport.PerformanceReport;
35 import com.android.dialer.util.CallUtil;
36 import com.google.auto.value.AutoValue;
37 import com.google.common.collect.ImmutableMap;
38 import com.google.protobuf.InvalidProtocolBufferException;
39 
40 /** Creates an intent to start a new outgoing call. */
41 @AutoValue
42 public abstract class CallIntent implements Parcelable {
43   private static int lightbringerButtonAppearInExpandedCallLogItemCount = 0;
44   private static int lightbringerButtonAppearInCollapsedCallLogItemCount = 0;
45   private static int lightbringerButtonAppearInSearchCount = 0;
46 
number()47   abstract Uri number();
48 
callSpecificAppData()49   abstract CallSpecificAppData callSpecificAppData();
50 
51   @Nullable
phoneAccountHandle()52   abstract PhoneAccountHandle phoneAccountHandle();
53 
isVideoCall()54   abstract boolean isVideoCall();
55 
56   @Nullable
callSubject()57   abstract String callSubject();
58 
allowAssistedDial()59   abstract boolean allowAssistedDial();
60 
stringInCallUiIntentExtras()61   abstract ImmutableMap<String, String> stringInCallUiIntentExtras();
62 
longInCallUiIntentExtras()63   abstract ImmutableMap<String, Long> longInCallUiIntentExtras();
64 
stringPlaceCallExtras()65   abstract ImmutableMap<String, String> stringPlaceCallExtras();
66 
longPlaceCallExtras()67   abstract ImmutableMap<String, Long> longPlaceCallExtras();
68 
builder()69   public static Builder builder() {
70     return new AutoValue_CallIntent.Builder().setIsVideoCall(false).setAllowAssistedDial(false);
71   }
72 
toBuilder()73   public abstract Builder toBuilder();
74 
75   /** Builder class for CallIntent info. */
76   @AutoValue.Builder
77   public abstract static class Builder {
setTelNumber(String number)78     public Builder setTelNumber(String number) {
79       return setNumber(CallUtil.getCallUri(Assert.isNotNull(number)));
80     }
81 
setVoicemailNumber(@ullable PhoneAccountHandle phoneAccountHandle)82     public Builder setVoicemailNumber(@Nullable PhoneAccountHandle phoneAccountHandle) {
83       return setNumber(Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null))
84           .setPhoneAccountHandle(phoneAccountHandle);
85     }
86 
setNumber(@onNull Uri number)87     public abstract Builder setNumber(@NonNull Uri number);
88 
setCallInitiationType(CallInitiationType.Type callInitiationType)89     public Builder setCallInitiationType(CallInitiationType.Type callInitiationType) {
90       return setCallSpecificAppData(
91           CallSpecificAppData.newBuilder().setCallInitiationType(callInitiationType).build());
92     }
93 
callSpecificAppData()94     abstract CallSpecificAppData callSpecificAppData();
95 
setCallSpecificAppData( @onNull CallSpecificAppData callSpecificAppData)96     public abstract Builder setCallSpecificAppData(
97         @NonNull CallSpecificAppData callSpecificAppData);
98 
setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)99     public abstract Builder setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle);
100 
setIsVideoCall(boolean isVideoCall)101     public abstract Builder setIsVideoCall(boolean isVideoCall);
102 
setCallSubject(String callSubject)103     public abstract Builder setCallSubject(String callSubject);
104 
setAllowAssistedDial(boolean allowAssistedDial)105     public abstract Builder setAllowAssistedDial(boolean allowAssistedDial);
106 
stringInCallUiIntentExtrasBuilder()107     abstract ImmutableMap.Builder<String, String> stringInCallUiIntentExtrasBuilder();
108 
longInCallUiIntentExtrasBuilder()109     abstract ImmutableMap.Builder<String, Long> longInCallUiIntentExtrasBuilder();
110 
addInCallUiIntentExtra(String key, String value)111     public Builder addInCallUiIntentExtra(String key, String value) {
112       stringInCallUiIntentExtrasBuilder().put(key, value);
113       return this;
114     }
115 
addInCallUiIntentExtra(String key, Long value)116     public Builder addInCallUiIntentExtra(String key, Long value) {
117       longInCallUiIntentExtrasBuilder().put(key, value);
118       return this;
119     }
120 
stringPlaceCallExtrasBuilder()121     abstract ImmutableMap.Builder<String, String> stringPlaceCallExtrasBuilder();
122 
longPlaceCallExtrasBuilder()123     abstract ImmutableMap.Builder<String, Long> longPlaceCallExtrasBuilder();
124 
addPlaceCallExtra(String key, String value)125     public Builder addPlaceCallExtra(String key, String value) {
126       stringPlaceCallExtrasBuilder().put(key, value);
127       return this;
128     }
129 
addPlaceCallExtra(String key, Long value)130     public Builder addPlaceCallExtra(String key, Long value) {
131       longPlaceCallExtrasBuilder().put(key, value);
132       return this;
133     }
134 
autoBuild()135     abstract CallIntent autoBuild();
136 
build()137     public Intent build() {
138       CallSpecificAppData.Builder builder =
139           CallSpecificAppData.newBuilder(callSpecificAppData())
140               .setLightbringerButtonAppearInExpandedCallLogItemCount(
141                   lightbringerButtonAppearInExpandedCallLogItemCount)
142               .setLightbringerButtonAppearInCollapsedCallLogItemCount(
143                   lightbringerButtonAppearInCollapsedCallLogItemCount)
144               .setLightbringerButtonAppearInSearchCount(lightbringerButtonAppearInSearchCount);
145       lightbringerButtonAppearInExpandedCallLogItemCount = 0;
146       lightbringerButtonAppearInCollapsedCallLogItemCount = 0;
147       lightbringerButtonAppearInSearchCount = 0;
148 
149       if (PerformanceReport.isRecording()) {
150         builder
151             .setTimeSinceAppLaunch(PerformanceReport.getTimeSinceAppLaunch())
152             .setTimeSinceFirstClick(PerformanceReport.getTimeSinceFirstClick())
153             .addAllUiActionsSinceAppLaunch(PerformanceReport.getActions())
154             .addAllUiActionTimestampsSinceAppLaunch(PerformanceReport.getActionTimestamps())
155             .setStartingTabIndex(PerformanceReport.getStartingTabIndex());
156         PerformanceReport.stopRecording();
157       }
158 
159       setCallSpecificAppData(builder.build());
160 
161       // Validate CallIntent.
162       CallIntent callIntent = autoBuild();
163       Assert.isNotNull(callIntent.number());
164       Assert.isNotNull(callIntent.callSpecificAppData());
165       Assert.checkArgument(
166           callIntent.callSpecificAppData().getCallInitiationType()
167               != CallInitiationType.Type.UNKNOWN_INITIATION);
168 
169       return autoBuild().newIntent();
170     }
171   }
172 
173   // Creates the intent which can start a call
newIntent()174   private Intent newIntent() {
175     Intent intent = new Intent(Intent.ACTION_CALL, number());
176 
177     intent.putExtra(
178         TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
179         isVideoCall() ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY);
180 
181     Bundle inCallUiIntentExtras = createInCallUiIntentExtras();
182     inCallUiIntentExtras.putLong(
183         Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime());
184 
185     intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, inCallUiIntentExtras);
186 
187     if (phoneAccountHandle() != null) {
188       intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle());
189     }
190 
191     if (!TextUtils.isEmpty(callSubject())) {
192       intent.putExtra(TelecomManager.EXTRA_CALL_SUBJECT, callSubject());
193     }
194 
195     intent.putExtras(createPlaceCallExtras());
196 
197     return intent;
198   }
199 
createInCallUiIntentExtras()200   private Bundle createInCallUiIntentExtras() {
201     Bundle bundle = new Bundle();
202     stringInCallUiIntentExtras().forEach(bundle::putString);
203     longInCallUiIntentExtras().forEach(bundle::putLong);
204     CallIntentParser.putCallSpecificAppData(bundle, callSpecificAppData());
205     return bundle;
206   }
207 
createPlaceCallExtras()208   private Bundle createPlaceCallExtras() {
209     Bundle bundle = new Bundle();
210     stringPlaceCallExtras().forEach(bundle::putString);
211     longPlaceCallExtras().forEach(bundle::putLong);
212     CallIntentParser.putCallSpecificAppData(bundle, callSpecificAppData());
213     return bundle;
214   }
215 
increaseLightbringerCallButtonAppearInExpandedCallLogItemCount()216   public static void increaseLightbringerCallButtonAppearInExpandedCallLogItemCount() {
217     CallIntent.lightbringerButtonAppearInExpandedCallLogItemCount++;
218   }
219 
increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount()220   public static void increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount() {
221     CallIntent.lightbringerButtonAppearInCollapsedCallLogItemCount++;
222   }
223 
increaseLightbringerCallButtonAppearInSearchCount()224   public static void increaseLightbringerCallButtonAppearInSearchCount() {
225     CallIntent.lightbringerButtonAppearInSearchCount++;
226   }
227 
228   @VisibleForTesting
getLightbringerButtonAppearInExpandedCallLogItemCount()229   public static int getLightbringerButtonAppearInExpandedCallLogItemCount() {
230     return lightbringerButtonAppearInExpandedCallLogItemCount;
231   }
232 
233   @VisibleForTesting
getLightbringerButtonAppearInCollapsedCallLogItemCount()234   public static int getLightbringerButtonAppearInCollapsedCallLogItemCount() {
235     return lightbringerButtonAppearInCollapsedCallLogItemCount;
236   }
237 
238   @VisibleForTesting
getLightbringerButtonAppearInSearchCount()239   public static int getLightbringerButtonAppearInSearchCount() {
240     return lightbringerButtonAppearInSearchCount;
241   }
242 
243   @VisibleForTesting(otherwise = VisibleForTesting.NONE)
clearLightbringerCounts()244   public static void clearLightbringerCounts() {
245     lightbringerButtonAppearInCollapsedCallLogItemCount = 0;
246     lightbringerButtonAppearInExpandedCallLogItemCount = 0;
247     lightbringerButtonAppearInSearchCount = 0;
248   }
249 
250   @Override
describeContents()251   public int describeContents() {
252     return 0;
253   }
254 
255   @Override
writeToParcel(Parcel dest, int flags)256   public void writeToParcel(Parcel dest, int flags) {
257     dest.writeParcelable(number(), flags);
258     dest.writeByteArray(callSpecificAppData().toByteArray());
259     dest.writeParcelable(phoneAccountHandle(), flags);
260     dest.writeInt(isVideoCall() ? 1 : 0);
261     dest.writeString(callSubject());
262     dest.writeInt(allowAssistedDial() ? 1 : 0);
263     Bundle stringInCallUiIntentExtrasBundle = new Bundle();
264     stringInCallUiIntentExtras().forEach(stringInCallUiIntentExtrasBundle::putString);
265     dest.writeBundle(stringInCallUiIntentExtrasBundle);
266     Bundle longInCallUiIntentExtrasBundle = new Bundle();
267     longInCallUiIntentExtras().forEach(longInCallUiIntentExtrasBundle::putLong);
268     dest.writeBundle(longInCallUiIntentExtrasBundle);
269   }
270 
271   // @TODO(justinmcclain): Investigate deleting the parcelable logic and instead switching
272   // to using an internal proto for serialization.
273   public static final Creator<CallIntent> CREATOR =
274       new Creator<CallIntent>() {
275         @Override
276         public CallIntent createFromParcel(Parcel source) {
277           CallIntent.Builder callIntentBuilder = builder();
278           ClassLoader classLoader = CallIntent.class.getClassLoader();
279           callIntentBuilder.setNumber(source.readParcelable(classLoader));
280           CallSpecificAppData data;
281           try {
282             data = CallSpecificAppData.parseFrom(source.createByteArray());
283           } catch (InvalidProtocolBufferException e) {
284             data = CallSpecificAppData.getDefaultInstance();
285           }
286           callIntentBuilder
287               .setCallSpecificAppData(data)
288               .setPhoneAccountHandle(source.readParcelable(classLoader))
289               .setIsVideoCall(source.readInt() != 0)
290               .setCallSubject(source.readString())
291               .setAllowAssistedDial(source.readInt() != 0);
292           Bundle stringInCallUiIntentExtrasBundle = source.readBundle(classLoader);
293           for (String key : stringInCallUiIntentExtrasBundle.keySet()) {
294             callIntentBuilder.addInCallUiIntentExtra(
295                 key, stringInCallUiIntentExtrasBundle.getString(key));
296           }
297           Bundle longInCallUiIntentExtrasBundle = source.readBundle(classLoader);
298           for (String key : longInCallUiIntentExtrasBundle.keySet()) {
299             callIntentBuilder.addInCallUiIntentExtra(
300                 key, longInCallUiIntentExtrasBundle.getLong(key));
301           }
302           return callIntentBuilder.autoBuild();
303         }
304 
305         @Override
306         public CallIntent[] newArray(int size) {
307           return new CallIntent[0];
308         }
309       };
310 }
311