1 /* 2 * Copyright (C) 2016 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.Call.Details; 29 import android.telecom.PhoneAccount; 30 import android.telecom.PhoneAccountHandle; 31 import android.telecom.TelecomManager; 32 import android.telecom.VideoProfile; 33 import android.text.TextUtils; 34 import com.android.dialer.callintent.CallInitiationType.Type; 35 import com.android.dialer.common.Assert; 36 import com.android.dialer.performancereport.PerformanceReport; 37 import com.android.dialer.util.CallUtil; 38 import com.google.protobuf.InvalidProtocolBufferException; 39 40 /** Creates an intent to start a new outgoing call. */ 41 public class CallIntentBuilder implements Parcelable { 42 private Uri uri; 43 private final CallSpecificAppData callSpecificAppData; 44 @Nullable private PhoneAccountHandle phoneAccountHandle; 45 private boolean isVideoCall; 46 private boolean isDuoCall; 47 private String callSubject; 48 private boolean allowAssistedDial; 49 50 private final Bundle inCallUiIntentExtras = new Bundle(); 51 private final Bundle placeCallExtras = new Bundle(); 52 53 private static int lightbringerButtonAppearInExpandedCallLogItemCount = 0; 54 private static int lightbringerButtonAppearInCollapsedCallLogItemCount = 0; 55 private static int lightbringerButtonAppearInSearchCount = 0; 56 CallIntentBuilder(@onNull Uri uri, @NonNull CallSpecificAppData callSpecificAppData)57 public CallIntentBuilder(@NonNull Uri uri, @NonNull CallSpecificAppData callSpecificAppData) { 58 this.uri = Assert.isNotNull(uri); 59 Assert.isNotNull(callSpecificAppData); 60 Assert.checkArgument( 61 callSpecificAppData.getCallInitiationType() != CallInitiationType.Type.UNKNOWN_INITIATION); 62 63 CallSpecificAppData.Builder builder = 64 CallSpecificAppData.newBuilder(callSpecificAppData) 65 .setLightbringerButtonAppearInExpandedCallLogItemCount( 66 lightbringerButtonAppearInExpandedCallLogItemCount) 67 .setLightbringerButtonAppearInCollapsedCallLogItemCount( 68 lightbringerButtonAppearInCollapsedCallLogItemCount) 69 .setLightbringerButtonAppearInSearchCount(lightbringerButtonAppearInSearchCount); 70 lightbringerButtonAppearInExpandedCallLogItemCount = 0; 71 lightbringerButtonAppearInCollapsedCallLogItemCount = 0; 72 lightbringerButtonAppearInSearchCount = 0; 73 74 if (PerformanceReport.isRecording()) { 75 builder 76 .setTimeSinceAppLaunch(PerformanceReport.getTimeSinceAppLaunch()) 77 .setTimeSinceFirstClick(PerformanceReport.getTimeSinceFirstClick()) 78 .addAllUiActionsSinceAppLaunch(PerformanceReport.getActions()) 79 .addAllUiActionTimestampsSinceAppLaunch(PerformanceReport.getActionTimestamps()) 80 .setStartingTabIndex(PerformanceReport.getStartingTabIndex()) 81 .build(); 82 PerformanceReport.stopRecording(); 83 } 84 85 this.callSpecificAppData = builder.build(); 86 } 87 CallIntentBuilder(@onNull Uri uri, CallInitiationType.Type callInitiationType)88 public CallIntentBuilder(@NonNull Uri uri, CallInitiationType.Type callInitiationType) { 89 this(uri, createCallSpecificAppData(callInitiationType)); 90 } 91 CallIntentBuilder( @onNull String number, @NonNull CallSpecificAppData callSpecificAppData)92 public CallIntentBuilder( 93 @NonNull String number, @NonNull CallSpecificAppData callSpecificAppData) { 94 this(CallUtil.getCallUri(Assert.isNotNull(number)), callSpecificAppData); 95 } 96 CallIntentBuilder(@onNull String number, CallInitiationType.Type callInitiationType)97 public CallIntentBuilder(@NonNull String number, CallInitiationType.Type callInitiationType) { 98 this(CallUtil.getCallUri(Assert.isNotNull(number)), callInitiationType); 99 } 100 CallIntentBuilder(@onNull Parcel parcel)101 public CallIntentBuilder(@NonNull Parcel parcel) { 102 ClassLoader classLoader = CallIntentBuilder.class.getClassLoader(); 103 uri = parcel.readParcelable(classLoader); 104 CallSpecificAppData data; 105 try { 106 data = CallSpecificAppData.parseFrom(parcel.createByteArray()); 107 } catch (InvalidProtocolBufferException e) { 108 data = createCallSpecificAppData(Type.UNKNOWN_INITIATION); 109 } 110 callSpecificAppData = data; 111 phoneAccountHandle = parcel.readParcelable(classLoader); 112 isVideoCall = parcel.readInt() != 0; 113 isDuoCall = parcel.readInt() != 0; 114 callSubject = parcel.readString(); 115 allowAssistedDial = parcel.readInt() != 0; 116 inCallUiIntentExtras.putAll(parcel.readBundle(classLoader)); 117 } 118 forVoicemail( @ullable PhoneAccountHandle phoneAccountHandle, CallInitiationType.Type callInitiationType)119 public static CallIntentBuilder forVoicemail( 120 @Nullable PhoneAccountHandle phoneAccountHandle, CallInitiationType.Type callInitiationType) { 121 return new CallIntentBuilder( 122 Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null), callInitiationType) 123 .setPhoneAccountHandle(phoneAccountHandle); 124 } 125 setUri(@onNull Uri uri)126 public void setUri(@NonNull Uri uri) { 127 this.uri = Assert.isNotNull(uri); 128 } 129 getUri()130 public Uri getUri() { 131 return uri; 132 } 133 getCallSpecificAppData()134 public CallSpecificAppData getCallSpecificAppData() { 135 return callSpecificAppData; 136 } 137 setPhoneAccountHandle(@ullable PhoneAccountHandle accountHandle)138 public CallIntentBuilder setPhoneAccountHandle(@Nullable PhoneAccountHandle accountHandle) { 139 this.phoneAccountHandle = accountHandle; 140 return this; 141 } 142 143 @Nullable getPhoneAccountHandle()144 public PhoneAccountHandle getPhoneAccountHandle() { 145 return phoneAccountHandle; 146 } 147 setIsVideoCall(boolean isVideoCall)148 public CallIntentBuilder setIsVideoCall(boolean isVideoCall) { 149 this.isVideoCall = isVideoCall; 150 return this; 151 } 152 isVideoCall()153 public boolean isVideoCall() { 154 return isVideoCall; 155 } 156 setIsDuoCall(boolean isDuoCall)157 public CallIntentBuilder setIsDuoCall(boolean isDuoCall) { 158 this.isDuoCall = isDuoCall; 159 return this; 160 } 161 isDuoCall()162 public boolean isDuoCall() { 163 return isDuoCall; 164 } 165 166 /** Default false. Should only be set to true if the number has a lookup URI. */ setAllowAssistedDial(boolean allowAssistedDial)167 public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) { 168 this.allowAssistedDial = allowAssistedDial; 169 return this; 170 } 171 isAssistedDialAllowed()172 public boolean isAssistedDialAllowed() { 173 return allowAssistedDial; 174 } 175 setCallSubject(String callSubject)176 public CallIntentBuilder setCallSubject(String callSubject) { 177 this.callSubject = callSubject; 178 return this; 179 } 180 getCallSubject()181 public String getCallSubject() { 182 return callSubject; 183 } 184 185 /** Additional data the in call UI can read with {@link Details#getIntentExtras()} */ getInCallUiIntentExtras()186 public Bundle getInCallUiIntentExtras() { 187 return inCallUiIntentExtras; 188 } 189 190 /** 191 * Other extras that should be used with {@link TelecomManager#placeCall(Uri, Bundle)}. This will 192 * override everything set by the CallIntentBuilder 193 */ getPlaceCallExtras()194 public Bundle getPlaceCallExtras() { 195 return placeCallExtras; 196 } 197 198 /** 199 * @deprecated Use {@link com.android.dialer.precall.PreCall#getIntent(android.content.Context, 200 * CallIntentBuilder)} instead. 201 */ 202 @Deprecated build()203 public Intent build() { 204 Intent intent = new Intent(Intent.ACTION_CALL, uri); 205 206 intent.putExtra( 207 TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 208 isVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY); 209 210 inCallUiIntentExtras.putLong( 211 Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime()); 212 CallIntentParser.putCallSpecificAppData(inCallUiIntentExtras, callSpecificAppData); 213 214 intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, inCallUiIntentExtras); 215 216 if (phoneAccountHandle != null) { 217 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); 218 } 219 220 if (!TextUtils.isEmpty(callSubject)) { 221 intent.putExtra(TelecomManager.EXTRA_CALL_SUBJECT, callSubject); 222 } 223 224 intent.putExtras(placeCallExtras); 225 226 return intent; 227 } 228 createCallSpecificAppData( CallInitiationType.Type callInitiationType)229 private static @NonNull CallSpecificAppData createCallSpecificAppData( 230 CallInitiationType.Type callInitiationType) { 231 CallSpecificAppData callSpecificAppData = 232 CallSpecificAppData.newBuilder().setCallInitiationType(callInitiationType).build(); 233 return callSpecificAppData; 234 } 235 increaseLightbringerCallButtonAppearInExpandedCallLogItemCount()236 public static void increaseLightbringerCallButtonAppearInExpandedCallLogItemCount() { 237 CallIntentBuilder.lightbringerButtonAppearInExpandedCallLogItemCount++; 238 } 239 increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount()240 public static void increaseLightbringerCallButtonAppearInCollapsedCallLogItemCount() { 241 CallIntentBuilder.lightbringerButtonAppearInCollapsedCallLogItemCount++; 242 } 243 increaseLightbringerCallButtonAppearInSearchCount()244 public static void increaseLightbringerCallButtonAppearInSearchCount() { 245 CallIntentBuilder.lightbringerButtonAppearInSearchCount++; 246 } 247 248 @VisibleForTesting getLightbringerButtonAppearInExpandedCallLogItemCount()249 public static int getLightbringerButtonAppearInExpandedCallLogItemCount() { 250 return lightbringerButtonAppearInExpandedCallLogItemCount; 251 } 252 253 @VisibleForTesting getLightbringerButtonAppearInCollapsedCallLogItemCount()254 public static int getLightbringerButtonAppearInCollapsedCallLogItemCount() { 255 return lightbringerButtonAppearInCollapsedCallLogItemCount; 256 } 257 258 @VisibleForTesting getLightbringerButtonAppearInSearchCount()259 public static int getLightbringerButtonAppearInSearchCount() { 260 return lightbringerButtonAppearInSearchCount; 261 } 262 263 @VisibleForTesting(otherwise = VisibleForTesting.NONE) clearLightbringerCounts()264 public static void clearLightbringerCounts() { 265 lightbringerButtonAppearInCollapsedCallLogItemCount = 0; 266 lightbringerButtonAppearInExpandedCallLogItemCount = 0; 267 lightbringerButtonAppearInSearchCount = 0; 268 } 269 270 @Override describeContents()271 public int describeContents() { 272 return 0; 273 } 274 275 @Override writeToParcel(Parcel dest, int flags)276 public void writeToParcel(Parcel dest, int flags) { 277 dest.writeParcelable(uri, flags); 278 dest.writeByteArray(callSpecificAppData.toByteArray()); 279 dest.writeParcelable(phoneAccountHandle, flags); 280 dest.writeInt(isVideoCall ? 1 : 0); 281 dest.writeInt(isDuoCall ? 1 : 0); 282 dest.writeString(callSubject); 283 dest.writeInt(allowAssistedDial ? 1 : 0); 284 dest.writeBundle(inCallUiIntentExtras); 285 } 286 287 public static final Creator<CallIntentBuilder> CREATOR = 288 new Creator<CallIntentBuilder>() { 289 @Override 290 public CallIntentBuilder createFromParcel(Parcel source) { 291 return new CallIntentBuilder(source); 292 } 293 294 @Override 295 public CallIntentBuilder[] newArray(int size) { 296 return new CallIntentBuilder[0]; 297 } 298 }; 299 } 300