diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2017-11-11 22:00:13 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-11-11 22:00:13 +0000 |
commit | 5e20ba7b1c6a9644da034b345000b37856d78125 (patch) | |
tree | a2cfecc9e0c1d1e920487a04f1e91acc8e7dfd8b /java/com | |
parent | 3d198bb28ae6b086f967619b25407f65a7f3ebe9 (diff) | |
parent | b0ed171b1c9d5b5d5e686b31be623c99ced15cf0 (diff) |
Merge changes Ide5ec431,Icf2f8fae
* changes:
Implement PreCallCoordinator
Make CallIntentBuilder parcelable
Diffstat (limited to 'java/com')
20 files changed, 699 insertions, 70 deletions
diff --git a/java/com/android/dialer/app/DialtactsActivity.java b/java/com/android/dialer/app/DialtactsActivity.java index 12c191e53..089ffd389 100644 --- a/java/com/android/dialer/app/DialtactsActivity.java +++ b/java/com/android/dialer/app/DialtactsActivity.java @@ -44,7 +44,6 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.telecom.PhoneAccount; -import android.telephony.TelephonyManager; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -90,7 +89,6 @@ import com.android.dialer.app.list.SmartDialSearchFragment; import com.android.dialer.app.settings.DialerSettingsActivity; import com.android.dialer.app.widget.ActionBarController; import com.android.dialer.app.widget.SearchEditTextLayout; -import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.callcomposer.CallComposerActivity; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.callintent.CallInitiationType; @@ -1521,11 +1519,7 @@ public class DialtactsActivity extends TransactionSafeActivity Intent intent = new CallIntentBuilder(phoneNumber, callSpecificAppData) .setIsVideoCall(isVideoCall) - .setAllowAssistedDial( - callSpecificAppData.getAllowAssistedDialing(), - ConcreteCreator.createNewAssistedDialingMediator( - getApplication().getSystemService(TelephonyManager.class), - getApplicationContext())) + .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing()) .build(); DialerUtils.startActivityWithErrorToast(this, intent); diff --git a/java/com/android/dialer/app/calllog/IntentProvider.java b/java/com/android/dialer/app/calllog/IntentProvider.java index 36e62c379..5180651da 100644 --- a/java/com/android/dialer/app/calllog/IntentProvider.java +++ b/java/com/android/dialer/app/calllog/IntentProvider.java @@ -26,7 +26,6 @@ import android.telecom.PhoneAccountHandle; import android.telephony.TelephonyManager; import com.android.contacts.common.model.Contact; import com.android.contacts.common.model.ContactLoader; -import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.calldetails.CallDetailsActivity; import com.android.dialer.calldetails.CallDetailsEntries; import com.android.dialer.callintent.CallInitiationType; @@ -67,8 +66,7 @@ public abstract class IntentProvider { @Override public Intent getIntent(Context context) { return new CallIntentBuilder(number, CallInitiationType.Type.CALL_LOG) - .setAllowAssistedDial( - true, ConcreteCreator.createNewAssistedDialingMediator(telephonyManager, context)) + .setAllowAssistedDial(true) .build(); } }; diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java index bd275df55..a02727ea8 100644 --- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java +++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java @@ -25,6 +25,7 @@ import com.android.dialer.enrichedcall.stub.StubEnrichedCallModule; import com.android.dialer.inject.ContextModule; import com.android.dialer.phonelookup.PhoneLookupModule; import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule; +import com.android.dialer.precall.impl.PreCallModule; import com.android.dialer.simulator.impl.SimulatorModule; import com.android.dialer.storage.StorageModule; import com.android.dialer.strictmode.impl.SystemStrictModeModule; @@ -43,6 +44,7 @@ import javax.inject.Singleton; DialerExecutorModule.class, PhoneLookupModule.class, PhoneNumberGeoUtilModule.class, + PreCallModule.class, SharedPrefConfigProviderModule.class, SimulatorModule.class, StorageModule.class, diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java index bc5036ff1..387fca530 100644 --- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java +++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java @@ -25,6 +25,7 @@ import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.main.MainComponent; import com.android.dialer.phonelookup.PhoneLookupComponent; import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent; +import com.android.dialer.precall.PreCallComponent; import com.android.dialer.simulator.SimulatorComponent; import com.android.dialer.storage.StorageComponent; import com.android.dialer.strictmode.StrictModeComponent; @@ -48,6 +49,7 @@ public interface BaseDialerRootComponent MapsComponent.HasComponent, PhoneLookupComponent.HasComponent, PhoneNumberGeoUtilComponent.HasComponent, + PreCallComponent.HasComponent, SimulatorComponent.HasComponent, StorageComponent.HasComponent, StrictModeComponent.HasComponent, diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java index c47a69bbd..273d1e4fc 100644 --- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java +++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java @@ -25,6 +25,7 @@ import com.android.dialer.enrichedcall.stub.StubEnrichedCallModule; import com.android.dialer.inject.ContextModule; import com.android.dialer.phonelookup.PhoneLookupModule; import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule; +import com.android.dialer.precall.impl.PreCallModule; import com.android.dialer.simulator.impl.SimulatorModule; import com.android.dialer.storage.StorageModule; import com.android.dialer.strictmode.impl.SystemStrictModeModule; @@ -47,6 +48,7 @@ import javax.inject.Singleton; DialerExecutorModule.class, PhoneLookupModule.class, // TODO(zachh): Module which uses APDL? PhoneNumberGeoUtilModule.class, + PreCallModule.class, SharedPrefConfigProviderModule.class, SimulatorModule.class, StorageModule.class, diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java index 3a3c9118a..6ba31e624 100644 --- a/java/com/android/dialer/calldetails/CallDetailsActivity.java +++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java @@ -30,10 +30,8 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar.OnMenuItemClickListener; -import android.telephony.TelephonyManager; import android.view.MenuItem; import android.widget.Toast; -import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; @@ -243,10 +241,7 @@ public class CallDetailsActivity extends AppCompatActivity CallIntentBuilder callIntentBuilder = new CallIntentBuilder(phoneNumber + postDialDigits, CallInitiationType.Type.CALL_DETAILS); if (canSupportedAssistedDialing) { - callIntentBuilder.setAllowAssistedDial( - true, - ConcreteCreator.createNewAssistedDialingMediator( - getSystemService(TelephonyManager.class), this)); + callIntentBuilder.setAllowAssistedDial(true); } DialerUtils.startActivityWithErrorToast(this, callIntentBuilder.build()); diff --git a/java/com/android/dialer/callintent/CallIntentBuilder.java b/java/com/android/dialer/callintent/CallIntentBuilder.java index 25a5803dc..aabeabdc8 100644 --- a/java/com/android/dialer/callintent/CallIntentBuilder.java +++ b/java/com/android/dialer/callintent/CallIntentBuilder.java @@ -16,11 +16,11 @@ package com.android.dialer.callintent; -import android.annotation.TargetApi; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -30,23 +30,22 @@ import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; import android.text.TextUtils; -import com.android.dialer.assisteddialing.AssistedDialingMediator; -import com.android.dialer.assisteddialing.TransformationInfo; +import com.android.dialer.callintent.CallInitiationType.Type; import com.android.dialer.common.Assert; -import com.android.dialer.compat.telephony.TelephonyManagerCompat; import com.android.dialer.performancereport.PerformanceReport; import com.android.dialer.util.CallUtil; -import java.util.Optional; +import com.google.protobuf.InvalidProtocolBufferException; /** Creates an intent to start a new outgoing call. */ -public class CallIntentBuilder { - private final Uri uri; +public class CallIntentBuilder implements Parcelable { + private Uri uri; private final CallSpecificAppData callSpecificAppData; @Nullable private PhoneAccountHandle phoneAccountHandle; private boolean isVideoCall; private String callSubject; private boolean allowAssistedDial; - private AssistedDialingMediator assistedDialingMediator; + + private final Bundle outgoingCallExtras = new Bundle(); private static int lightbringerButtonAppearInExpandedCallLogItemCount = 0; private static int lightbringerButtonAppearInCollapsedCallLogItemCount = 0; @@ -96,6 +95,23 @@ public class CallIntentBuilder { this(CallUtil.getCallUri(Assert.isNotNull(number)), callInitiationType); } + public CallIntentBuilder(@NonNull Parcel parcel) { + ClassLoader classLoader = CallIntentBuilder.class.getClassLoader(); + uri = parcel.readParcelable(classLoader); + CallSpecificAppData data; + try { + data = CallSpecificAppData.parseFrom(parcel.createByteArray()); + } catch (InvalidProtocolBufferException e) { + data = createCallSpecificAppData(Type.UNKNOWN_INITIATION); + } + callSpecificAppData = data; + phoneAccountHandle = parcel.readParcelable(classLoader); + isVideoCall = parcel.readInt() != 0; + callSubject = parcel.readString(); + allowAssistedDial = parcel.readInt() != 0; + outgoingCallExtras.putAll(parcel.readBundle(classLoader)); + } + public static CallIntentBuilder forVoicemail( @Nullable PhoneAccountHandle phoneAccountHandle, CallInitiationType.Type callInitiationType) { return new CallIntentBuilder( @@ -103,6 +119,14 @@ public class CallIntentBuilder { .setPhoneAccountHandle(phoneAccountHandle); } + public void setUri(@NonNull Uri uri) { + this.uri = Assert.isNotNull(uri); + } + + public Uri getUri() { + return uri; + } + public CallSpecificAppData getCallSpecificAppData() { return callSpecificAppData; } @@ -112,40 +136,54 @@ public class CallIntentBuilder { return this; } + @Nullable + public PhoneAccountHandle getPhoneAccountHandle() { + return phoneAccountHandle; + } + public CallIntentBuilder setIsVideoCall(boolean isVideoCall) { this.isVideoCall = isVideoCall; return this; } - public CallIntentBuilder setAllowAssistedDial( - boolean allowAssistedDial, @NonNull AssistedDialingMediator assistedDialingMediator) { - this.assistedDialingMediator = Assert.isNotNull(assistedDialingMediator); + public boolean isVideoCall() { + return isVideoCall; + } + + public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) { this.allowAssistedDial = allowAssistedDial; return this; } + public boolean isAssistedDialAllowed() { + return allowAssistedDial; + } + public CallIntentBuilder setCallSubject(String callSubject) { this.callSubject = callSubject; return this; } + public String getCallSubject() { + return callSubject; + } + + public Bundle getOutgoingCallExtras() { + return outgoingCallExtras; + } + public Intent build() { Intent intent = new Intent(Intent.ACTION_CALL, uri); - Bundle extras = new Bundle(); - if (allowAssistedDial - && this.assistedDialingMediator != null - && this.assistedDialingMediator.isPlatformEligible()) { - intent = buildAssistedDialingParameters(intent, extras); - } intent.putExtra( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, isVideoCall ? VideoProfile.STATE_BIDIRECTIONAL : VideoProfile.STATE_AUDIO_ONLY); - extras.putLong(Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime()); - CallIntentParser.putCallSpecificAppData(extras, callSpecificAppData); + outgoingCallExtras.putLong( + Constants.EXTRA_CALL_CREATED_TIME_MILLIS, SystemClock.elapsedRealtime()); + CallIntentParser.putCallSpecificAppData(outgoingCallExtras, callSpecificAppData); - intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); + intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, outgoingCallExtras); if (phoneAccountHandle != null) { intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle); @@ -158,26 +196,6 @@ public class CallIntentBuilder { return intent; } - @SuppressWarnings("AndroidApiChecker") // Use of optional - @TargetApi(Build.VERSION_CODES.N) - private Intent buildAssistedDialingParameters(Intent intent, Bundle extras) { - extras.putBoolean(TelephonyManagerCompat.ALLOW_ASSISTED_DIAL, true); - String phoneNumber = - uri.getScheme().equals(PhoneAccount.SCHEME_TEL) ? uri.getSchemeSpecificPart() : ""; - Optional<TransformationInfo> transformedNumber = - assistedDialingMediator.attemptAssistedDial(phoneNumber); - if (transformedNumber.isPresent()) { - Bundle assistedDialingExtras = transformedNumber.get().toBundle(); - extras.putBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, true); - extras.putBundle(TelephonyManagerCompat.ASSISTED_DIALING_EXTRAS, assistedDialingExtras); - intent = - new Intent( - Intent.ACTION_CALL, - CallUtil.getCallUri(Assert.isNotNull(transformedNumber.get().transformedNumber()))); - } - return intent; - } - private static @NonNull CallSpecificAppData createCallSpecificAppData( CallInitiationType.Type callInitiationType) { CallSpecificAppData callSpecificAppData = @@ -218,4 +236,33 @@ public class CallIntentBuilder { lightbringerButtonAppearInExpandedCallLogItemCount = 0; lightbringerButtonAppearInSearchCount = 0; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(uri, flags); + dest.writeByteArray(callSpecificAppData.toByteArray()); + dest.writeParcelable(phoneAccountHandle, flags); + dest.writeInt(isVideoCall ? 1 : 0); + dest.writeString(callSubject); + dest.writeInt(allowAssistedDial ? 1 : 0); + dest.writeBundle(outgoingCallExtras); + } + + public static final Creator<CallIntentBuilder> CREATOR = + new Creator<CallIntentBuilder>() { + @Override + public CallIntentBuilder createFromParcel(Parcel source) { + return new CallIntentBuilder(source); + } + + @Override + public CallIntentBuilder[] newArray(int size) { + return new CallIntentBuilder[0]; + } + }; } diff --git a/java/com/android/dialer/interactions/PhoneNumberInteraction.java b/java/com/android/dialer/interactions/PhoneNumberInteraction.java index ac744cce7..255f6c380 100644 --- a/java/com/android/dialer/interactions/PhoneNumberInteraction.java +++ b/java/com/android/dialer/interactions/PhoneNumberInteraction.java @@ -41,7 +41,6 @@ import android.provider.ContactsContract.RawContacts; import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; import android.support.v4.app.ActivityCompat; -import android.telephony.TelephonyManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -53,7 +52,6 @@ import com.android.contacts.common.Collapser; import com.android.contacts.common.Collapser.Collapsible; import com.android.contacts.common.MoreContactUtils; import com.android.contacts.common.util.ContactDisplayUtils; -import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; import com.android.dialer.callintent.CallIntentParser; @@ -187,10 +185,7 @@ public class PhoneNumberInteraction implements OnLoadCompleteListener<Cursor> { intent = new CallIntentBuilder(phoneNumber, callSpecificAppData) .setIsVideoCall(isVideoCall) - .setAllowAssistedDial( - callSpecificAppData.getAllowAssistedDialing(), - ConcreteCreator.createNewAssistedDialingMediator( - context.getSystemService(TelephonyManager.class), context)) + .setAllowAssistedDial(callSpecificAppData.getAllowAssistedDialing()) .build(); break; } diff --git a/java/com/android/dialer/precall/PreCall.java b/java/com/android/dialer/precall/PreCall.java new file mode 100644 index 000000000..93fd8e9b6 --- /dev/null +++ b/java/com/android/dialer/precall/PreCall.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall; + +import android.content.Context; +import android.content.Intent; +import android.support.annotation.MainThread; +import android.support.annotation.NonNull; +import com.android.dialer.callintent.CallIntentBuilder; +import com.google.common.collect.ImmutableList; + +/** Interface to prepare a {@link CallIntentBuilder} before placing the call with telecom. */ +public interface PreCall { + + /** + * @return a list of {@link PreCallAction} in execution order for the {@link PreCallCoordinator} + * to run. + */ + @NonNull + ImmutableList<PreCallAction> getActions(); + + /** + * @return a intent when started as activity, will perform the pre-call actions and then place a + * call. TODO(twyen): if all actions do not require an UI, return a intent that will place the + * call directly instead. + */ + @NonNull + @MainThread + Intent buildIntent(Context context, CallIntentBuilder builder); +} diff --git a/java/com/android/dialer/precall/PreCallAction.java b/java/com/android/dialer/precall/PreCallAction.java new file mode 100644 index 000000000..9434694a4 --- /dev/null +++ b/java/com/android/dialer/precall/PreCallAction.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall; + +import android.support.annotation.MainThread; +import com.android.dialer.callintent.CallIntentBuilder; + +/** + * An action to perform before the call is made. The action should inspect and modify the {@link + * CallIntentBuilder} to generate full information for the call. For example, showing a dialog to + * select the phone account on a multi-SIM device, ask if RTT should be enabled, or rewrite the + * number for roaming calls. + */ +public interface PreCallAction { + + /** + * Runs the action. Should block on the main thread until the action is finished. If the action is + * not instantaneous, {@link PreCallCoordinator#startPendingAction()} should be called to release + * the thread and continue later. + */ + @MainThread + void run(PreCallCoordinator coordinator); + + /** + * Called when the UI is being paused when a {@link PreCallCoordinator.PendingAction} is started, + * and the action is going to be discarded. If the action is showing a dialog the dialog should be + * dismissed. The action should not retain state, a new instance of the action will be re-run when + * the UI is resumed. + */ + @MainThread + void onDiscard(); +} diff --git a/java/com/android/dialer/precall/PreCallComponent.java b/java/com/android/dialer/precall/PreCallComponent.java new file mode 100644 index 000000000..00adde56d --- /dev/null +++ b/java/com/android/dialer/precall/PreCallComponent.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall; + +import android.content.Context; +import com.android.dialer.inject.HasRootComponent; +import dagger.Subcomponent; + +/** Daggaer component for {@link PreCall} */ +@Subcomponent +public abstract class PreCallComponent { + public abstract PreCall getPreCall(); + + public static PreCallComponent get(Context context) { + return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) + .preCallActionsComponent(); + } + + /** Used to refer to the root application component. */ + public interface HasComponent { + PreCallComponent preCallActionsComponent(); + } +} diff --git a/java/com/android/dialer/precall/PreCallCoordinator.java b/java/com/android/dialer/precall/PreCallCoordinator.java new file mode 100644 index 000000000..b5e9e8594 --- /dev/null +++ b/java/com/android/dialer/precall/PreCallCoordinator.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall; + +import android.app.Activity; +import android.support.annotation.MainThread; +import android.support.annotation.NonNull; +import com.android.dialer.callintent.CallIntentBuilder; + +/** + * Runs {@link PreCallAction} one by one to prepare a {@link + * com.android.dialer.callintent.CallIntentBuilder} for a call. + */ +public interface PreCallCoordinator { + + @NonNull + CallIntentBuilder getBuilder(); + + /** + * @return the activity to attach the UI to. Returns {@link null} if the coordinator is running on + * headless mode. TODO(twyen): implement headless mode. + */ + @NonNull + Activity getActivity(); + + /** + * Called by a {@link PreCallAction} to abort the call. For example, the user has dismissed the + * dialog and must start over. + */ + void abortCall(); + + /** + * Callback from a {@link PreCallAction} to signal the action started by {@link + * PreCallCoordinator#startPendingAction()} has finished. + */ + interface PendingAction { + + @MainThread + void finish(); + } + + /** + * Called by the current running {@link PreCallAction} to release the main thread and resume + * pre-call later. + * + * @return a {@link PendingAction} which {@link PendingAction#finish(boolean)} should be called to + * resume pre-call. For example the action shows a dialog to the user, startPendingAction() + * should be called as the action will not be finished immediately. When the dialog is + * completed, {@code finish()} is then called to continue the next step. + */ + @MainThread + @NonNull + PendingAction startPendingAction(); +} diff --git a/java/com/android/dialer/precall/impl/AndroidManifest.xml b/java/com/android/dialer/precall/impl/AndroidManifest.xml new file mode 100644 index 000000000..d3d0f538d --- /dev/null +++ b/java/com/android/dialer/precall/impl/AndroidManifest.xml @@ -0,0 +1,29 @@ +<!-- + ~ Copyright (C) 2017 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.dialer.precall.impl"> + + <application> + <activity + android:exported="false" + android:name="com.android.dialer.precall.impl.PreCallActivity" + android:excludeFromRecents="true" + android:noHistory="true" + android:theme="@style/Theme.PreCall.DialogHolder"> + </activity> + </application> +</manifest> diff --git a/java/com/android/dialer/precall/impl/PreCallActivity.java b/java/com/android/dialer/precall/impl/PreCallActivity.java new file mode 100644 index 000000000..938d31d5f --- /dev/null +++ b/java/com/android/dialer/precall/impl/PreCallActivity.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall.impl; + +import android.app.Activity; +import android.os.Bundle; +import android.support.annotation.Nullable; + +/** A transparent activity to host dialogs for {@link PreCallCoordinatorImpl} */ +public class PreCallActivity extends Activity { + + private PreCallCoordinatorImpl preCallCoordinator; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + preCallCoordinator = new PreCallCoordinatorImpl(this); + preCallCoordinator.onCreate(getIntent(), savedInstanceState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + preCallCoordinator.onRestoreInstanceState(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + preCallCoordinator.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + preCallCoordinator.onPause(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + preCallCoordinator.onSaveInstanceState(outState); + } +} diff --git a/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java b/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java new file mode 100644 index 000000000..25083ef0b --- /dev/null +++ b/java/com/android/dialer/precall/impl/PreCallCoordinatorImpl.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall.impl; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import com.android.dialer.precall.PreCallAction; +import com.android.dialer.precall.PreCallComponent; +import com.android.dialer.precall.PreCallCoordinator; +import com.android.dialer.telecom.TelecomUtil; +import com.google.common.collect.ImmutableList; + +/** + * Implements {@link PreCallCoordinator}. Listens to the life cycle of {@link PreCallActivity} to + * save/restore states. + */ +public class PreCallCoordinatorImpl implements PreCallCoordinator { + + private static final String SAVED_STATE_CURRENT_ACTION = "current_action"; + + static final String EXTRA_CALL_INTENT_BUILDER = "extra_call_intent_builder"; + + @NonNull private final Activity activity; + + private CallIntentBuilder builder; + private ImmutableList<PreCallAction> actions; + private int currentActionIndex = 0; + private PreCallAction currentAction; + private PendingAction pendingAction; + private boolean aborted = false; + + PreCallCoordinatorImpl(@NonNull Activity activity) { + this.activity = Assert.isNotNull(activity); + } + + void onCreate(Intent intent, @Nullable Bundle savedInstanceState) { + LogUtil.enterBlock("PreCallCoordinatorImpl.onCreate"); + if (savedInstanceState != null) { + currentActionIndex = savedInstanceState.getInt(SAVED_STATE_CURRENT_ACTION); + builder = Assert.isNotNull(savedInstanceState.getParcelable(EXTRA_CALL_INTENT_BUILDER)); + } else { + builder = Assert.isNotNull(intent.getParcelableExtra(EXTRA_CALL_INTENT_BUILDER)); + } + actions = PreCallComponent.get(activity).getPreCall().getActions(); + } + + void onRestoreInstanceState(Bundle savedInstanceState) { + currentActionIndex = savedInstanceState.getInt(SAVED_STATE_CURRENT_ACTION); + builder = savedInstanceState.getParcelable(EXTRA_CALL_INTENT_BUILDER); + } + + void onResume() { + runNextAction(); + } + + void onPause() { + if (currentAction != null) { + currentAction.onDiscard(); + } + currentAction = null; + } + + void onSaveInstanceState(Bundle outState) { + outState.putInt(SAVED_STATE_CURRENT_ACTION, currentActionIndex); + outState.putParcelable(EXTRA_CALL_INTENT_BUILDER, builder); + } + + private void runNextAction() { + LogUtil.enterBlock("PreCallCoordinatorImpl.runNextAction"); + Assert.checkArgument(currentAction == null); + if (currentActionIndex >= actions.size()) { + TelecomUtil.placeCall(activity, builder.build()); + activity.finish(); + return; + } + LogUtil.i("PreCallCoordinatorImpl.runNextAction", "running " + actions.get(currentActionIndex)); + currentAction = actions.get(currentActionIndex); + actions.get(currentActionIndex).run(this); + if (pendingAction == null) { + onActionFinished(); + } + } + + private void onActionFinished() { + LogUtil.enterBlock("PreCallCoordinatorImpl.onActionFinished"); + Assert.isNotNull(currentAction); + currentAction = null; + currentActionIndex++; + if (!aborted) { + runNextAction(); + } else { + activity.finish(); + } + } + + @Override + public void abortCall() { + Assert.checkState(currentAction != null); + aborted = true; + } + + @NonNull + @Override + public CallIntentBuilder getBuilder() { + return builder; + } + + @NonNull + @Override + public Activity getActivity() { + return activity; + } + + @Override + @NonNull + public PendingAction startPendingAction() { + Assert.isMainThread(); + Assert.isNotNull(currentAction); + Assert.checkArgument(pendingAction == null); + pendingAction = new PendingActionImpl(); + return pendingAction; + } + + private class PendingActionImpl implements PendingAction { + + @Override + public void finish() { + Assert.checkArgument(pendingAction == this); + pendingAction = null; + onActionFinished(); + } + } +} diff --git a/java/com/android/dialer/precall/impl/PreCallImpl.java b/java/com/android/dialer/precall/impl/PreCallImpl.java new file mode 100644 index 000000000..ac9750ef2 --- /dev/null +++ b/java/com/android/dialer/precall/impl/PreCallImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall.impl; + +import android.content.Context; +import android.content.Intent; +import android.support.annotation.NonNull; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.precall.PreCall; +import com.android.dialer.precall.PreCallAction; +import com.google.common.collect.ImmutableList; +import javax.inject.Inject; + +/** Implementation of {@link PreCall} */ +public class PreCallImpl implements PreCall { + + @Inject + PreCallImpl() {} + + @Override + public ImmutableList<PreCallAction> getActions() { + return ImmutableList.of(); + } + + @NonNull + @Override + public Intent buildIntent(Context context, CallIntentBuilder builder) { + Intent intent = new Intent(context, PreCallActivity.class); + intent.putExtra(PreCallCoordinatorImpl.EXTRA_CALL_INTENT_BUILDER, builder); + return intent; + } +} diff --git a/java/com/android/dialer/precall/impl/PreCallModule.java b/java/com/android/dialer/precall/impl/PreCallModule.java new file mode 100644 index 000000000..608cd5a8f --- /dev/null +++ b/java/com/android/dialer/precall/impl/PreCallModule.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall.impl; + +import com.android.dialer.precall.PreCall; +import dagger.Binds; +import dagger.Module; +import javax.inject.Singleton; + +/** Dagger module for {@link PreCall}. */ +@Module +public abstract class PreCallModule { + + @Binds + @Singleton + public abstract PreCall bindPreCall(PreCallImpl simulator); +} diff --git a/java/com/android/dialer/precall/impl/res/values/styles.xml b/java/com/android/dialer/precall/impl/res/values/styles.xml new file mode 100644 index 000000000..dd41265a4 --- /dev/null +++ b/java/com/android/dialer/precall/impl/res/values/styles.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<resources> + <style name="Theme.PreCall.DialogHolder" parent="DialerThemeBase.NoActionBar"> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowActivityTransitions">false</item> + <item name="android:windowIsTranslucent">true</item> + + <item name="android:statusBarColor">@android:color/transparent</item> + <item name="android:navigationBarColor">@android:color/transparent</item> + <item name="android:windowDrawsSystemBarBackgrounds">true</item> + </style> + +</resources> diff --git a/java/com/android/dialer/precall/testing/TestPreCallModule.java b/java/com/android/dialer/precall/testing/TestPreCallModule.java new file mode 100644 index 000000000..b777de890 --- /dev/null +++ b/java/com/android/dialer/precall/testing/TestPreCallModule.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.precall.testing; + +import android.content.Context; +import android.content.Intent; +import android.support.annotation.NonNull; +import com.android.dialer.callintent.CallIntentBuilder; +import com.android.dialer.precall.PreCall; +import com.android.dialer.precall.PreCallAction; +import com.google.common.collect.ImmutableList; +import dagger.Module; +import dagger.Provides; +import javax.inject.Singleton; + +/** Provides test implementation of {@link PreCall} */ +@Module +public class TestPreCallModule { + private static PreCall preCall = new StubPreCall(); + + public static void setPreCall(PreCall preCall) { + TestPreCallModule.preCall = preCall; + } + + @Provides + @Singleton + public static PreCall providePreCall() { + return preCall; + } + + private static class StubPreCall implements PreCall { + + @NonNull + @Override + public ImmutableList<PreCallAction> getActions() { + return ImmutableList.of(); + } + + @NonNull + @Override + public Intent buildIntent(Context context, CallIntentBuilder builder) { + return builder.build(); + } + } +} diff --git a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java index cd42a7476..c0a6700eb 100644 --- a/java/com/android/dialer/searchfragment/list/NewSearchFragment.java +++ b/java/com/android/dialer/searchfragment/list/NewSearchFragment.java @@ -32,7 +32,6 @@ import android.support.annotation.VisibleForTesting; import android.support.v13.app.FragmentCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -44,7 +43,6 @@ import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import com.android.contacts.common.extensions.PhoneDirectoryExtenderAccessor; import com.android.dialer.animation.AnimUtils; -import com.android.dialer.assisteddialing.ConcreteCreator; import com.android.dialer.callcomposer.CallComposerActivity; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; @@ -488,11 +486,7 @@ public final class NewSearchFragment extends Fragment Intent intent = new CallIntentBuilder(phoneNumber, callSpecificAppData) .setIsVideoCall(isVideoCall) - .setAllowAssistedDial( - allowAssistedDial, - ConcreteCreator.createNewAssistedDialingMediator( - getContext().getSystemService(TelephonyManager.class), - getContext().getApplicationContext())) + .setAllowAssistedDial(allowAssistedDial) .build(); DialerUtils.startActivityWithErrorToast(getActivity(), intent); FragmentUtils.getParentUnsafe(this, SearchFragmentListener.class).onCallPlaced(); |