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