summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/com/android/contacts/common/res/layout/select_account_list_item.xml3
-rw-r--r--java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java187
-rw-r--r--java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java55
-rw-r--r--java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto54
-rw-r--r--java/com/android/dialer/activecalls/ActiveCallInfo.java48
-rw-r--r--java/com/android/dialer/activecalls/ActiveCalls.java34
-rw-r--r--java/com/android/dialer/activecalls/ActiveCallsComponent.java40
-rw-r--r--java/com/android/dialer/activecalls/ActiveCallsModule.java34
-rw-r--r--java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java45
-rw-r--r--java/com/android/dialer/binary/aosp/AospDialerRootComponent.java2
-rw-r--r--java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java4
-rw-r--r--java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java2
-rw-r--r--java/com/android/dialer/commandline/CommandLineModule.java7
-rw-r--r--java/com/android/dialer/commandline/impl/ActiveCallsCommand.java67
-rw-r--r--java/com/android/dialer/common/FragmentUtils.java5
-rw-r--r--java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java11
-rw-r--r--java/com/android/dialer/logging/dialer_impression.proto12
-rw-r--r--java/com/android/dialer/main/impl/NewMainActivityPeer.java23
-rw-r--r--java/com/android/dialer/main/impl/OldMainActivityPeer.java23
-rw-r--r--java/com/android/dialer/oem/CequintCallerIdManager.java56
-rw-r--r--java/com/android/dialer/phonelookup/PhoneLookupModule.java3
-rw-r--r--java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java90
-rw-r--r--java/com/android/dialer/phonelookup/phone_lookup_info.proto14
-rw-r--r--java/com/android/dialer/phonenumbercache/ContactInfoHelper.java12
-rw-r--r--java/com/android/dialer/precall/impl/CallingAccountSelector.java203
-rw-r--r--java/com/android/dialer/precall/impl/res/values/strings.xml6
-rw-r--r--java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java45
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialAdapter.java5
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialFragment.java17
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java8
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java27
-rw-r--r--java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java9
-rw-r--r--java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java63
-rw-r--r--java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml21
-rw-r--r--java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml21
-rw-r--r--java/com/android/dialer/theme/res/values/colors.xml6
-rw-r--r--java/com/android/incallui/ActiveCallsCallListListener.java73
-rw-r--r--java/com/android/incallui/ConferenceParticipantListAdapter.java2
-rw-r--r--java/com/android/incallui/ContactInfoCache.java12
-rw-r--r--java/com/android/incallui/InCallActivity.java182
-rw-r--r--java/com/android/incallui/InCallPresenter.java20
-rw-r--r--java/com/android/incallui/call/DialerCall.java2
-rw-r--r--java/com/android/incallui/res/layout/caller_in_conference.xml2
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatFragment.java5
-rw-r--r--java/com/android/incallui/telecomeventui/AndroidManifest.xml13
-rw-r--r--java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java101
-rw-r--r--java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java82
47 files changed, 1341 insertions, 415 deletions
diff --git a/java/com/android/contacts/common/res/layout/select_account_list_item.xml b/java/com/android/contacts/common/res/layout/select_account_list_item.xml
index 84cb1fd66..98e7c5454 100644
--- a/java/com/android/contacts/common/res/layout/select_account_list_item.xml
+++ b/java/com/android/contacts/common/res/layout/select_account_list_item.xml
@@ -54,14 +54,15 @@
android:includeFontPadding="false"
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/dialer_secondary_text_color"
android:visibility="gone"/>
<TextView
android:id="@+id/hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
- android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/dialer_secondary_text_color"
android:visibility="gone"/>
</LinearLayout>
diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
index 295aa963a..3ee21ccea 100644
--- a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
+++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
@@ -47,10 +47,9 @@ import com.android.contacts.common.R;
import com.android.contacts.common.compat.PhoneAccountCompat;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
+import com.android.dialer.protos.ProtoParsers;
import com.android.dialer.telecom.TelecomUtil;
import com.google.common.base.Optional;
-import java.util.ArrayList;
-import java.util.List;
/**
* Dialog that allows the user to select a phone accounts for a given action. Optionally provides
@@ -58,128 +57,74 @@ import java.util.List;
*/
public class SelectPhoneAccountDialogFragment extends DialogFragment {
- private static final String ARG_TITLE_RES_ID = "title_res_id";
- private static final String ARG_CAN_SET_DEFAULT = "can_set_default";
- private static final String ARG_SET_DEFAULT_RES_ID = "set_default_res_id";
- private static final String ARG_ACCOUNT_HANDLES = "account_handles";
+ @VisibleForTesting public static final String ARG_OPTIONS = "options";
+
private static final String ARG_IS_DEFAULT_CHECKED = "is_default_checked";
- private static final String ARG_LISTENER = "listener";
- private static final String ARG_CALL_ID = "call_id";
- private static final String ARG_HINTS = "hints";
-
- private List<PhoneAccountHandle> mAccountHandles;
- private List<String> mHints;
- private boolean mIsSelected;
- private boolean mIsDefaultChecked;
- private SelectPhoneAccountListener mListener;
-
- public SelectPhoneAccountDialogFragment() {}
-
- /**
- * Create new fragment instance with default title and no option to set as default.
- *
- * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
- * @param listener The listener for the results of the account selection.
- */
- public static SelectPhoneAccountDialogFragment newInstance(
- List<PhoneAccountHandle> accountHandles,
- SelectPhoneAccountListener listener,
- @Nullable String callId) {
- return newInstance(
- R.string.select_account_dialog_title, false, 0, accountHandles, listener, callId, null);
- }
- /**
- * Create new fragment instance. This method also allows specifying a custom title and "set
- * default" checkbox.
- *
- * @param titleResId The resource ID for the string to use in the title of the dialog.
- * @param canSetDefault {@code true} if the dialog should include an option to set the selection
- * as the default. False otherwise.
- * @param setDefaultResId The resource ID for the string to use in the "set as default" checkbox
- * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
- * @param listener The listener for the results of the account selection.
- * @param callId The callId to be passed back to the listener in {@link
- * SelectPhoneAccountListener#EXTRA_CALL_ID}
- * @param hints Additional information to be shown underneath the phone account to help user
- * choose. Index must match {@code accountHandles}
- */
+ private SelectPhoneAccountDialogOptions options =
+ SelectPhoneAccountDialogOptions.getDefaultInstance();
+ private SelectPhoneAccountListener listener;
+
+ private boolean isDefaultChecked;
+ private boolean isSelected;
+
+ /** Create new fragment instance. */
public static SelectPhoneAccountDialogFragment newInstance(
- int titleResId,
- boolean canSetDefault,
- int setDefaultResId,
- List<PhoneAccountHandle> accountHandles,
- SelectPhoneAccountListener listener,
- @Nullable String callId,
- @Nullable List<String> hints) {
- ArrayList<PhoneAccountHandle> accountHandlesCopy = new ArrayList<>();
- if (accountHandles != null) {
- accountHandlesCopy.addAll(accountHandles);
- }
+ SelectPhoneAccountDialogOptions options, SelectPhoneAccountListener listener) {
SelectPhoneAccountDialogFragment fragment = new SelectPhoneAccountDialogFragment();
- final Bundle args = new Bundle();
- args.putInt(ARG_TITLE_RES_ID, titleResId);
- args.putBoolean(ARG_CAN_SET_DEFAULT, canSetDefault);
- if (setDefaultResId != 0) {
- args.putInt(ARG_SET_DEFAULT_RES_ID, setDefaultResId);
- }
- args.putParcelableArrayList(ARG_ACCOUNT_HANDLES, accountHandlesCopy);
- args.putParcelable(ARG_LISTENER, listener);
- args.putString(ARG_CALL_ID, callId);
- if (hints != null) {
- args.putStringArrayList(ARG_HINTS, new ArrayList<>(hints));
- }
- fragment.setArguments(args);
fragment.setListener(listener);
+ Bundle arguments = new Bundle();
+ ProtoParsers.put(arguments, ARG_OPTIONS, options);
+ fragment.setArguments(arguments);
return fragment;
}
public void setListener(SelectPhoneAccountListener listener) {
- mListener = listener;
+ this.listener = listener;
}
@Nullable
@VisibleForTesting
public SelectPhoneAccountListener getListener() {
- return mListener;
+ return listener;
}
@VisibleForTesting
public boolean canSetDefault() {
- return getArguments().getBoolean(ARG_CAN_SET_DEFAULT);
+ return options.getCanSetDefault();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(ARG_IS_DEFAULT_CHECKED, mIsDefaultChecked);
+ outState.putBoolean(ARG_IS_DEFAULT_CHECKED, isDefaultChecked);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- int titleResId = getArguments().getInt(ARG_TITLE_RES_ID);
- boolean canSetDefault = getArguments().getBoolean(ARG_CAN_SET_DEFAULT);
- mAccountHandles = getArguments().getParcelableArrayList(ARG_ACCOUNT_HANDLES);
- mListener = getArguments().getParcelable(ARG_LISTENER);
- mHints = getArguments().getStringArrayList(ARG_HINTS);
+ options =
+ ProtoParsers.getTrusted(
+ getArguments(), ARG_OPTIONS, SelectPhoneAccountDialogOptions.getDefaultInstance());
if (savedInstanceState != null) {
- mIsDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED);
+ isDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED);
}
- mIsSelected = false;
+ isSelected = false;
final DialogInterface.OnClickListener selectionListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mIsSelected = true;
- PhoneAccountHandle selectedAccountHandle = mAccountHandles.get(which);
+ isSelected = true;
+ PhoneAccountHandle selectedAccountHandle =
+ SelectPhoneAccountDialogOptionsUtil.getPhoneAccountHandle(
+ options.getEntriesList().get(which));
Bundle result = new Bundle();
result.putParcelable(
SelectPhoneAccountListener.EXTRA_SELECTED_ACCOUNT_HANDLE, selectedAccountHandle);
- result.putBoolean(SelectPhoneAccountListener.EXTRA_SET_DEFAULT, mIsDefaultChecked);
+ result.putBoolean(SelectPhoneAccountListener.EXTRA_SET_DEFAULT, isDefaultChecked);
result.putString(SelectPhoneAccountListener.EXTRA_CALL_ID, getCallId());
- if (mListener != null) {
- mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result);
+ if (listener != null) {
+ listener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result);
}
}
};
@@ -188,22 +133,23 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton check, boolean isChecked) {
- mIsDefaultChecked = isChecked;
+ isDefaultChecked = isChecked;
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
ListAdapter selectAccountListAdapter =
new SelectAccountListAdapter(
- builder.getContext(), R.layout.select_account_list_item, mAccountHandles, mHints);
+ builder.getContext(), R.layout.select_account_list_item, options);
AlertDialog dialog =
builder
- .setTitle(titleResId)
+ .setTitle(
+ options.hasTitle() ? options.getTitle() : R.string.select_account_dialog_title)
.setAdapter(selectAccountListAdapter, selectionListener)
.create();
- if (canSetDefault) {
+ if (options.getCanSetDefault()) {
// Generate custom checkbox view, lint suppressed since no appropriate parent (is dialog)
@SuppressLint("InflateParams")
LinearLayout checkboxLayout =
@@ -213,11 +159,13 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
CheckBox checkBox = checkboxLayout.findViewById(R.id.default_account_checkbox_view);
checkBox.setOnCheckedChangeListener(checkListener);
- checkBox.setChecked(mIsDefaultChecked);
+ checkBox.setChecked(isDefaultChecked);
TextView textView = checkboxLayout.findViewById(R.id.default_account_checkbox_text);
int setDefaultResId =
- getArguments().getInt(ARG_SET_DEFAULT_RES_ID, R.string.set_default_account);
+ options.hasSetDefaultLabel()
+ ? options.getSetDefaultLabel()
+ : R.string.set_default_account;
textView.setText(setDefaultResId);
textView.setOnClickListener((view) -> checkBox.performClick());
checkboxLayout.setOnClickListener((view) -> checkBox.performClick());
@@ -230,17 +178,17 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
@Override
public void onCancel(DialogInterface dialog) {
- if (!mIsSelected && mListener != null) {
+ if (!isSelected && listener != null) {
Bundle result = new Bundle();
result.putString(SelectPhoneAccountListener.EXTRA_CALL_ID, getCallId());
- mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, result);
+ listener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, result);
}
super.onCancel(dialog);
}
@Nullable
private String getCallId() {
- return getArguments().getString(ARG_CALL_ID);
+ return options.getCallId();
}
public static class SelectPhoneAccountListener extends ResultReceiver {
@@ -274,22 +222,30 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
public void onDialogDismissed(@Nullable String callId) {}
}
- private static class SelectAccountListAdapter extends ArrayAdapter<PhoneAccountHandle> {
+ static class SelectAccountListAdapter
+ extends ArrayAdapter<SelectPhoneAccountDialogOptions.Entry> {
private int mResId;
- private final List<String> mHints;
+ private final SelectPhoneAccountDialogOptions options;
SelectAccountListAdapter(
- Context context,
- int resource,
- List<PhoneAccountHandle> accountHandles,
- @Nullable List<String> hints) {
- super(context, resource, accountHandles);
- mHints = hints;
+ Context context, int resource, SelectPhoneAccountDialogOptions options) {
+ super(context, resource, options.getEntriesList());
+ this.options = options;
mResId = resource;
}
@Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return options.getEntries(position).getEnabled();
+ }
+
+ @Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -311,7 +267,9 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
holder = (ViewHolder) rowView.getTag();
}
- PhoneAccountHandle accountHandle = getItem(position);
+ SelectPhoneAccountDialogOptions.Entry entry = getItem(position);
+ PhoneAccountHandle accountHandle =
+ SelectPhoneAccountDialogOptionsUtil.getPhoneAccountHandle(entry);
PhoneAccount account =
getContext().getSystemService(TelecomManager.class).getPhoneAccount(accountHandle);
if (account == null) {
@@ -331,18 +289,17 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
}
holder.imageView.setImageDrawable(
PhoneAccountCompat.createIconDrawable(account, getContext()));
- if (mHints != null && position < mHints.size()) {
- String hint = mHints.get(position);
- if (TextUtils.isEmpty(hint)) {
- holder.hintTextView.setVisibility(View.GONE);
- } else {
- holder.hintTextView.setVisibility(View.VISIBLE);
- holder.hintTextView.setText(hint);
- }
- } else {
+
+ if (TextUtils.isEmpty(entry.getHint())) {
holder.hintTextView.setVisibility(View.GONE);
+ } else {
+ holder.hintTextView.setVisibility(View.VISIBLE);
+ holder.hintTextView.setText(entry.getHint());
}
-
+ holder.labelTextView.setEnabled(entry.getEnabled());
+ holder.numberTextView.setEnabled(entry.getEnabled());
+ holder.hintTextView.setEnabled(entry.getEnabled());
+ holder.imageView.setImageAlpha(entry.getEnabled() ? 255 : 97 /* 38%*/);
return rowView;
}
@@ -356,7 +313,7 @@ public class SelectPhoneAccountDialogFragment extends DialogFragment {
return info.get().getCountryIso().toUpperCase();
}
- private static final class ViewHolder {
+ static final class ViewHolder {
TextView labelTextView;
TextView numberTextView;
diff --git a/java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java
new file mode 100644
index 000000000..5a44ae7f8
--- /dev/null
+++ b/java/com/android/contacts/common/widget/SelectPhoneAccountDialogOptionsUtil.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.contacts.common.widget;
+
+import android.telecom.PhoneAccountHandle;
+import com.android.dialer.common.Assert;
+import com.android.dialer.telecom.TelecomUtil;
+import java.util.Collection;
+
+/** Provides common operation on a {@link SelectPhoneAccountDialogOptions} */
+public final class SelectPhoneAccountDialogOptionsUtil {
+ private SelectPhoneAccountDialogOptionsUtil() {}
+
+ public static PhoneAccountHandle getPhoneAccountHandle(
+ SelectPhoneAccountDialogOptions.Entry entry) {
+ return Assert.isNotNull(
+ TelecomUtil.composePhoneAccountHandle(
+ entry.getPhoneAccountHandleComponentName(), entry.getPhoneAccountHandleId()));
+ }
+
+ public static SelectPhoneAccountDialogOptions.Entry.Builder setPhoneAccountHandle(
+ SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder,
+ PhoneAccountHandle phoneAccountHandle) {
+ entryBuilder.setPhoneAccountHandleComponentName(
+ phoneAccountHandle.getComponentName().flattenToString());
+ entryBuilder.setPhoneAccountHandleId(phoneAccountHandle.getId());
+ return entryBuilder;
+ }
+
+ public static SelectPhoneAccountDialogOptions.Builder builderWithAccounts(
+ Collection<PhoneAccountHandle> phoneAccountHandles) {
+ SelectPhoneAccountDialogOptions.Builder optionsBuilder =
+ SelectPhoneAccountDialogOptions.newBuilder();
+ for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
+ optionsBuilder.addEntries(
+ SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle(
+ SelectPhoneAccountDialogOptions.Entry.newBuilder(), phoneAccountHandle));
+ }
+ return optionsBuilder;
+ }
+}
diff --git a/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto b/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto
new file mode 100644
index 000000000..cc40c64b4
--- /dev/null
+++ b/java/com/android/contacts/common/widget/select_phone_account_dialog_options.proto
@@ -0,0 +1,54 @@
+// Copyright (C) 2018 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
+
+syntax = "proto2";
+
+option java_package = "com.android.contacts.common.widget";
+option java_multiple_files = true;
+option optimize_for = LITE_RUNTIME;
+
+
+package com.android.contacts.common.widget;
+
+// Parameters for SelectPhoneAccountDialogFragment
+message SelectPhoneAccountDialogOptions {
+ // The resource ID for the title. Defaults to
+ // R.string.select_account_dialog_title
+ optional int32 title = 1;
+ // Whether the dialog should include a "set as default" checkbox. Defaults to
+ // false
+ optional bool can_set_default = 2;
+ // The label on the "set as default" checkbox. Defaults
+ // R.string.set_default_account
+ optional int32 set_default_label = 3;
+ // The call ID to pass back to the callback
+ optional string call_id = 4;
+ // Phone accounts to show in the dialog
+ repeated Entry entries = 5;
+
+ message Entry {
+ // PhoneAccountHandle.getComponentName().flattenToString()
+ optional string phone_account_handle_component_name = 1;
+ // PhoneAccountHandle.getId()
+ optional string phone_account_handle_id = 2;
+ // The hint to show under the phone account, for example showing the user
+ // the account was selected frequently before.
+ optional string hint = 3;
+ // Whether the account is actually selectable. Defaults to true. Sometimes
+ // an account will be temporarily unusable, for example the user is already
+ // in a call so the other SIM cannot be used. Hint should also be set to
+ // inform the user why the account is unavailable.
+ optional bool enabled = 4 [default = true];
+ }
+} \ No newline at end of file
diff --git a/java/com/android/dialer/activecalls/ActiveCallInfo.java b/java/com/android/dialer/activecalls/ActiveCallInfo.java
new file mode 100644
index 000000000..d4f76b393
--- /dev/null
+++ b/java/com/android/dialer/activecalls/ActiveCallInfo.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.activecalls;
+
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+
+/** Info of an active call */
+@AutoValue
+@SuppressWarnings("Guava")
+public abstract class ActiveCallInfo {
+
+ /** The {@link PhoneAccountHandle} the call is made with */
+ public abstract Optional<PhoneAccountHandle> phoneAccountHandle();
+
+ public static Builder builder() {
+ return new AutoValue_ActiveCallInfo.Builder();
+ }
+
+ /** Builder for {@link ActiveCallInfo}. Only In Call UI should create ActiveCallInfo */
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ public Builder setPhoneAccountHandle(@Nullable PhoneAccountHandle phoneAccountHandle) {
+ return setPhoneAccountHandle(Optional.fromNullable(phoneAccountHandle));
+ }
+
+ public abstract Builder setPhoneAccountHandle(Optional<PhoneAccountHandle> phoneAccountHandle);
+
+ public abstract ActiveCallInfo build();
+ }
+}
diff --git a/java/com/android/dialer/activecalls/ActiveCalls.java b/java/com/android/dialer/activecalls/ActiveCalls.java
new file mode 100644
index 000000000..600839c73
--- /dev/null
+++ b/java/com/android/dialer/activecalls/ActiveCalls.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.activecalls;
+
+import android.support.annotation.MainThread;
+import com.google.common.collect.ImmutableList;
+
+/** Exposes information about current active calls to the whole dialer. */
+public interface ActiveCalls {
+
+ /**
+ * Return a list of current active calls. Any call that is not disconnected is regarded as active.
+ * Ordering of elements are not guaranteed.
+ */
+ ImmutableList<ActiveCallInfo> getActiveCalls();
+
+ /** Should only be called by in call UI. */
+ @MainThread
+ void setActiveCalls(ImmutableList<ActiveCallInfo> activeCalls);
+}
diff --git a/java/com/android/dialer/activecalls/ActiveCallsComponent.java b/java/com/android/dialer/activecalls/ActiveCallsComponent.java
new file mode 100644
index 000000000..99e0e9493
--- /dev/null
+++ b/java/com/android/dialer/activecalls/ActiveCallsComponent.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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.activecalls;
+
+import android.content.Context;
+import com.android.dialer.inject.HasRootComponent;
+import com.android.dialer.inject.IncludeInDialerRoot;
+import dagger.Subcomponent;
+
+/** Component for {@link ActiveCalls} */
+@Subcomponent
+public abstract class ActiveCallsComponent {
+
+ public abstract ActiveCalls activeCalls();
+
+ public static ActiveCallsComponent get(Context context) {
+ return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component())
+ .activeCallsComponent();
+ }
+
+ /** Used to refer to the root application component. */
+ @IncludeInDialerRoot
+ public interface HasComponent {
+ ActiveCallsComponent activeCallsComponent();
+ }
+}
diff --git a/java/com/android/dialer/activecalls/ActiveCallsModule.java b/java/com/android/dialer/activecalls/ActiveCallsModule.java
new file mode 100644
index 000000000..4d7f44858
--- /dev/null
+++ b/java/com/android/dialer/activecalls/ActiveCallsModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.activecalls;
+
+import com.android.dialer.activecalls.impl.ActiveCallsImpl;
+import com.android.dialer.inject.DialerVariant;
+import com.android.dialer.inject.InstallIn;
+import dagger.Binds;
+import dagger.Module;
+import javax.inject.Singleton;
+
+/** Module for {@link ActiveCallsComponent} */
+@Module
+@InstallIn(variants = DialerVariant.DIALER_TEST) // TODO(weijiaxu): put all variants.
+public abstract class ActiveCallsModule {
+
+ @Singleton
+ @Binds
+ public abstract ActiveCalls to(ActiveCallsImpl impl);
+}
diff --git a/java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java b/java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java
new file mode 100644
index 000000000..3449cc8b0
--- /dev/null
+++ b/java/com/android/dialer/activecalls/impl/ActiveCallsImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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.activecalls.impl;
+
+import android.support.annotation.MainThread;
+import com.android.dialer.activecalls.ActiveCallInfo;
+import com.android.dialer.activecalls.ActiveCalls;
+import com.android.dialer.common.Assert;
+import com.google.common.collect.ImmutableList;
+import javax.inject.Inject;
+
+/** Implementation of {@link ActiveCalls} */
+public class ActiveCallsImpl implements ActiveCalls {
+
+ ImmutableList<ActiveCallInfo> activeCalls = ImmutableList.of();
+
+ @Inject
+ ActiveCallsImpl() {}
+
+ @Override
+ public ImmutableList<ActiveCallInfo> getActiveCalls() {
+ return activeCalls;
+ }
+
+ @Override
+ @MainThread
+ public void setActiveCalls(ImmutableList<ActiveCallInfo> activeCalls) {
+ Assert.isMainThread();
+ this.activeCalls = Assert.isNotNull(activeCalls);
+ }
+}
diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java
index 21a282ded..e1021894f 100644
--- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java
+++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java
@@ -17,6 +17,7 @@
package com.android.dialer.binary.aosp;
import com.android.bubble.stub.StubBubbleModule;
+import com.android.dialer.activecalls.ActiveCallsModule;
import com.android.dialer.binary.basecomponent.BaseDialerRootComponent;
import com.android.dialer.calllog.CallLogModule;
import com.android.dialer.calllog.config.CallLogConfigModule;
@@ -49,6 +50,7 @@ import javax.inject.Singleton;
@Singleton
@Component(
modules = {
+ ActiveCallsModule.class,
CallLogModule.class,
CallLogConfigModule.class,
CommandLineModule.class,
diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
index 11e952cbc..75ddaf7f0 100644
--- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
+++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
@@ -17,6 +17,7 @@
package com.android.dialer.binary.basecomponent;
import com.android.bubble.BubbleComponent;
+import com.android.dialer.activecalls.ActiveCallsComponent;
import com.android.dialer.calllog.CallLogComponent;
import com.android.dialer.calllog.config.CallLogConfigComponent;
import com.android.dialer.calllog.database.CallLogDatabaseComponent;
@@ -50,7 +51,8 @@ import com.android.voicemail.VoicemailComponent;
* from this component.
*/
public interface BaseDialerRootComponent
- extends BluetoothDeviceProviderComponent.HasComponent,
+ extends ActiveCallsComponent.HasComponent,
+ BluetoothDeviceProviderComponent.HasComponent,
BubbleComponent.HasComponent,
CallLocationComponent.HasComponent,
CallLogComponent.HasComponent,
diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java
index 0da2f9577..bdbdeb9dd 100644
--- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java
+++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java
@@ -17,6 +17,7 @@
package com.android.dialer.binary.google;
import com.android.bubble.stub.StubBubbleModule;
+import com.android.dialer.activecalls.ActiveCallsModule;
import com.android.dialer.binary.basecomponent.BaseDialerRootComponent;
import com.android.dialer.calllog.CallLogModule;
import com.android.dialer.calllog.config.CallLogConfigModule;
@@ -52,6 +53,7 @@ import javax.inject.Singleton;
@Singleton
@Component(
modules = {
+ ActiveCallsModule.class,
CallLocationModule.class,
CallLogModule.class,
CallLogConfigModule.class,
diff --git a/java/com/android/dialer/commandline/CommandLineModule.java b/java/com/android/dialer/commandline/CommandLineModule.java
index 915578722..c78de21e5 100644
--- a/java/com/android/dialer/commandline/CommandLineModule.java
+++ b/java/com/android/dialer/commandline/CommandLineModule.java
@@ -16,6 +16,7 @@
package com.android.dialer.commandline;
+import com.android.dialer.commandline.impl.ActiveCallsCommand;
import com.android.dialer.commandline.impl.BlockingCommand;
import com.android.dialer.commandline.impl.CallCommand;
import com.android.dialer.commandline.impl.Echo;
@@ -45,6 +46,7 @@ public abstract class CommandLineModule {
private final Echo echo;
private final BlockingCommand blockingCommand;
private final CallCommand callCommand;
+ private final ActiveCallsCommand activeCallsCommand;
@Inject
AospCommandInjector(
@@ -52,12 +54,14 @@ public abstract class CommandLineModule {
Version version,
Echo echo,
BlockingCommand blockingCommand,
- CallCommand callCommand) {
+ CallCommand callCommand,
+ ActiveCallsCommand activeCallsCommand) {
this.help = help;
this.version = version;
this.echo = echo;
this.blockingCommand = blockingCommand;
this.callCommand = callCommand;
+ this.activeCallsCommand = activeCallsCommand;
}
public CommandSupplier.Builder inject(CommandSupplier.Builder builder) {
@@ -66,6 +70,7 @@ public abstract class CommandLineModule {
builder.addCommand("echo", echo);
builder.addCommand("blocking", blockingCommand);
builder.addCommand("call", callCommand);
+ builder.addCommand("activecalls", activeCallsCommand);
return builder;
}
}
diff --git a/java/com/android/dialer/commandline/impl/ActiveCallsCommand.java b/java/com/android/dialer/commandline/impl/ActiveCallsCommand.java
new file mode 100644
index 000000000..81641ed50
--- /dev/null
+++ b/java/com/android/dialer/commandline/impl/ActiveCallsCommand.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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.commandline.impl;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import com.android.dialer.activecalls.ActiveCallsComponent;
+import com.android.dialer.commandline.Arguments;
+import com.android.dialer.commandline.Command;
+import com.android.dialer.inject.ApplicationContext;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import javax.inject.Inject;
+
+/** Manipulates {@link com.android.dialer.activecalls.ActiveCalls} */
+public class ActiveCallsCommand implements Command {
+
+ private final Context appContext;
+
+ @Inject
+ ActiveCallsCommand(@ApplicationContext Context appContext) {
+ this.appContext = appContext;
+ }
+
+ @NonNull
+ @Override
+ public String getShortDescription() {
+ return "manipulate active calls";
+ }
+
+ @NonNull
+ @Override
+ public String getUsage() {
+ return "activecalls list";
+ }
+
+ @Override
+ public ListenableFuture<String> run(Arguments args) throws IllegalCommandLineArgumentException {
+ if (args.getPositionals().isEmpty()) {
+ return Futures.immediateFuture(getUsage());
+ }
+
+ String command = args.getPositionals().get(0);
+
+ switch (command) {
+ case "list":
+ return Futures.immediateFuture(
+ ActiveCallsComponent.get(appContext).activeCalls().getActiveCalls().toString());
+ default:
+ throw new IllegalCommandLineArgumentException("unknown command " + command);
+ }
+ }
+}
diff --git a/java/com/android/dialer/common/FragmentUtils.java b/java/com/android/dialer/common/FragmentUtils.java
index c07d9a799..aa4441eeb 100644
--- a/java/com/android/dialer/common/FragmentUtils.java
+++ b/java/com/android/dialer/common/FragmentUtils.java
@@ -59,6 +59,11 @@ public class FragmentUtils {
@SuppressWarnings("unchecked") // Casts are checked using runtime methods
T parent = ((FragmentUtilListener) fragment.getActivity()).getImpl(callbackInterface);
return parent;
+ } else if (fragment.getActivity() instanceof MainActivityPeer.PeerSupplier) {
+ MainActivityPeer peer = ((MainActivityPeer.PeerSupplier) fragment.getActivity()).getPeer();
+ if (peer instanceof FragmentUtilListener) {
+ return ((FragmentUtilListener) peer).getImpl(callbackInterface);
+ }
}
return null;
}
diff --git a/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java b/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java
index 9929ddd3b..d2652ee66 100644
--- a/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java
+++ b/java/com/android/dialer/dialpadview/SpecialCharSequenceMgr.java
@@ -56,6 +56,7 @@ import com.android.contacts.common.database.NoNullCursorAsyncQueryHandler;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener;
+import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.telephony.TelephonyManagerCompat;
@@ -234,10 +235,12 @@ public class SpecialCharSequenceMgr {
} else {
SelectPhoneAccountListener callback =
new HandleAdnEntryAccountSelectedCallback(applicationContext, handler, sc);
-
DialogFragment dialogFragment =
SelectPhoneAccountDialogFragment.newInstance(
- subscriptionAccountHandles, callback, null);
+ SelectPhoneAccountDialogOptionsUtil.builderWithAccounts(
+ subscriptionAccountHandles)
+ .build(),
+ callback);
dialogFragment.show(((Activity) context).getFragmentManager(), TAG_SELECT_ACCT_FRAGMENT);
}
@@ -292,7 +295,9 @@ public class SpecialCharSequenceMgr {
DialogFragment dialogFragment =
SelectPhoneAccountDialogFragment.newInstance(
- subscriptionAccountHandles, listener, null);
+ SelectPhoneAccountDialogOptionsUtil.builderWithAccounts(subscriptionAccountHandles)
+ .build(),
+ listener);
dialogFragment.show(((Activity) context).getFragmentManager(), TAG_SELECT_ACCT_FRAGMENT);
}
return true;
diff --git a/java/com/android/dialer/logging/dialer_impression.proto b/java/com/android/dialer/logging/dialer_impression.proto
index 5d40bb1ea..7cd22079c 100644
--- a/java/com/android/dialer/logging/dialer_impression.proto
+++ b/java/com/android/dialer/logging/dialer_impression.proto
@@ -12,7 +12,7 @@ message DialerImpression {
// Event enums to be used for Impression Logging in Dialer.
// It's perfectly acceptable for this enum to be large
// Values should be from 1000 to 100000.
- // Next Tag: 1387
+ // Next Tag: 1392
enum Type {
UNKNOWN_AOSP_EVENT_TYPE = 1000;
@@ -626,7 +626,11 @@ message DialerImpression {
DUAL_SIM_SELECTION_NON_SUGGESTED_SIM_SELECTED = 1304;
DUAL_SIM_SELECTION_PREFERRED_SET = 1305;
DUAL_SIM_SELECTION_PREFERRED_USED = 1306;
+ DUAL_SIM_SELECTION_PREFERRED_NOT_SELECTABLE = 1389;
DUAL_SIM_SELECTION_GLOBAL_USED = 1307;
+ DUAL_SIM_SELECTION_GLOBAL_NOT_SELECTABLE = 1390;
+ DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED = 1322;
+ DUAL_SIM_SELECTION_SUGGESTION_AUTO_NOT_SELECTABLE = 1391;
DUO_CALL_LOG_SET_UP_INSTALL = 1308;
DUO_CALL_LOG_SET_UP_ACTIVATE = 1309;
@@ -655,8 +659,6 @@ message DialerImpression {
// Drag bubble to bottom and end call
BUBBLE_V2_BOTTOM_ACTION_END_CALL = 1321;
- DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED = 1322;
-
// Bubble appears
BUBBLE_V2_SHOW = 1323;
@@ -764,5 +766,9 @@ message DialerImpression {
RTT_MID_CALL_ACCEPTED = 1385;
// Mid call RTT request rejected.
RTT_MID_CALL_REJECTED = 1386;
+
+ // Send button clicked in RTT call, this includes send button on keyboard.
+ RTT_SEND_BUTTON_CLICKED = 1387;
+ RTT_KEYBOARD_SEND_BUTTON_CLICKED = 1388;
}
}
diff --git a/java/com/android/dialer/main/impl/NewMainActivityPeer.java b/java/com/android/dialer/main/impl/NewMainActivityPeer.java
index 0ab69a443..f2d6fa6d3 100644
--- a/java/com/android/dialer/main/impl/NewMainActivityPeer.java
+++ b/java/com/android/dialer/main/impl/NewMainActivityPeer.java
@@ -29,7 +29,6 @@ import com.android.dialer.main.MainActivityPeer;
import com.android.dialer.main.impl.bottomnav.BottomNavBar;
import com.android.dialer.main.impl.bottomnav.BottomNavBar.OnBottomNavTabSelectedListener;
import com.android.dialer.main.impl.bottomnav.BottomNavBar.TabIndex;
-import com.android.dialer.speeddial.SpeedDialFragment;
import com.android.dialer.voicemail.listui.NewVoicemailFragment;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
@@ -106,16 +105,18 @@ public class NewMainActivityPeer implements MainActivityPeer {
@Override
public void onSpeedDialSelected() {
hideAllFragments();
- SpeedDialFragment fragment =
- (SpeedDialFragment) supportFragmentManager.findFragmentByTag(SPEED_DIAL_TAG);
- if (fragment == null) {
- supportFragmentManager
- .beginTransaction()
- .add(R.id.fragment_container, SpeedDialFragment.newInstance(), SPEED_DIAL_TAG)
- .commit();
- } else {
- supportFragmentManager.beginTransaction().show(fragment).commit();
- }
+ // TODO(calderwoodra): Since we aren't using fragment utils in this peer, let's disable
+ // speed dial until we figure out a solution.
+ // SpeedDialFragment fragment =
+ // (SpeedDialFragment) supportFragmentManager.findFragmentByTag(SPEED_DIAL_TAG);
+ // if (fragment == null) {
+ // supportFragmentManager
+ // .beginTransaction()
+ // .add(R.id.fragment_container, SpeedDialFragment.newInstance(), SPEED_DIAL_TAG)
+ // .commit();
+ // } else {
+ // supportFragmentManager.beginTransaction().show(fragment).commit();
+ // }
}
@Override
diff --git a/java/com/android/dialer/main/impl/OldMainActivityPeer.java b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
index 1c0cad0b0..9ac351094 100644
--- a/java/com/android/dialer/main/impl/OldMainActivityPeer.java
+++ b/java/com/android/dialer/main/impl/OldMainActivityPeer.java
@@ -183,6 +183,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
// Speed Dial
private MainOnPhoneNumberPickerActionListener onPhoneNumberPickerActionListener;
private MainOldSpeedDialFragmentHost oldSpeedDialFragmentHost;
+ private MainSpeedDialFragmentHost speedDialFragmentHost;
/** Language the device was in last time {@link #onSaveInstanceState(Bundle)} was called. */
private String savedLanguageCode;
@@ -293,6 +294,7 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
activity.findViewById(R.id.remove_view),
activity.findViewById(R.id.search_view_container),
toolbar);
+ speedDialFragmentHost = new MainSpeedDialFragmentHost(toolbar);
lastTabController = new LastTabController(activity, bottomNav, showVoicemailTab);
@@ -639,6 +641,8 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
return (T) oldSpeedDialFragmentHost;
} else if (callbackInterface.isInstance(searchController)) {
return (T) searchController;
+ } else if (callbackInterface.isInstance(speedDialFragmentHost)) {
+ return (T) speedDialFragmentHost;
} else {
return null;
}
@@ -1191,6 +1195,25 @@ public class OldMainActivityPeer implements MainActivityPeer, FragmentUtilListen
}
/**
+ * Handles the callbacks for {@link SpeedDialFragment}.
+ *
+ * @see SpeedDialFragment.HostInterface
+ */
+ private static final class MainSpeedDialFragmentHost implements SpeedDialFragment.HostInterface {
+
+ private final MainToolbar toolbar;
+
+ MainSpeedDialFragmentHost(MainToolbar toolbar) {
+ this.toolbar = toolbar;
+ }
+
+ @Override
+ public void setHasFrequents(boolean hasFrequents) {
+ toolbar.showClearFrequents(hasFrequents);
+ }
+ }
+
+ /**
* Implementation of {@link OnBottomNavTabSelectedListener} that handles logic for showing each of
* the main tabs and FAB.
*
diff --git a/java/com/android/dialer/oem/CequintCallerIdManager.java b/java/com/android/dialer/oem/CequintCallerIdManager.java
index ee865bc14..55cafc15e 100644
--- a/java/com/android/dialer/oem/CequintCallerIdManager.java
+++ b/java/com/android/dialer/oem/CequintCallerIdManager.java
@@ -30,6 +30,7 @@ import android.text.TextUtils;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.configprovider.ConfigProviderBindings;
+import com.google.auto.value.AutoValue;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -70,20 +71,37 @@ public class CequintCallerIdManager {
// TODO(wangqi): Revisit it and maybe remove it if it's not necessary.
private final ConcurrentHashMap<String, CequintCallerIdContact> callLogCache;
- /** Cequint caller id contact information. */
- public static class CequintCallerIdContact {
- public final String name;
- public final String geoDescription;
- public final String imageUrl;
+ /** Cequint caller ID contact information. */
+ @AutoValue
+ public abstract static class CequintCallerIdContact {
- private CequintCallerIdContact(String name, String geoDescription, String imageUrl) {
- this.name = name;
- this.geoDescription = geoDescription;
- this.imageUrl = imageUrl;
+ public abstract String name();
+
+ /**
+ * Description of the geolocation (e.g., "Mountain View, CA"), which is for display purpose
+ * only.
+ */
+ public abstract String geolocation();
+
+ public abstract String photoUri();
+
+ static Builder builder() {
+ return new AutoValue_CequintCallerIdManager_CequintCallerIdContact.Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setName(String name);
+
+ abstract Builder setGeolocation(String geolocation);
+
+ abstract Builder setPhotoUri(String photoUri);
+
+ abstract CequintCallerIdContact build();
}
}
- /** Check whether Cequint Caller Id provider package is available and enabled. */
+ /** Check whether Cequint Caller ID provider package is available and enabled. */
@AnyThread
public static synchronized boolean isCequintCallerIdEnabled(@NonNull Context context) {
if (!ConfigProviderBindings.get(context).getBoolean(CONFIG_CALLER_ID_ENABLED, true)) {
@@ -175,22 +193,26 @@ public class CequintCallerIdManager {
String name = getString(cursor, cursor.getColumnIndex(NAME));
String firstName = getString(cursor, cursor.getColumnIndex(FIRST_NAME));
String lastName = getString(cursor, cursor.getColumnIndex(LAST_NAME));
- String imageUrl = getString(cursor, cursor.getColumnIndex(IMAGE));
+ String photoUri = getString(cursor, cursor.getColumnIndex(IMAGE));
String displayName = getString(cursor, cursor.getColumnIndex(DISPLAY_NAME));
String contactName =
TextUtils.isEmpty(displayName)
? generateDisplayName(firstName, lastName, company, name)
: displayName;
- String geoDescription = getGeoDescription(city, state, stateAbbr, country);
+ String geolocation = getGeolocation(city, state, stateAbbr, country);
LogUtil.d(
"CequintCallerIdManager.lookup",
"number: %s, contact name: %s, geo: %s, photo url: %s",
LogUtil.sanitizePhoneNumber(number),
LogUtil.sanitizePii(contactName),
- LogUtil.sanitizePii(geoDescription),
- imageUrl);
- return new CequintCallerIdContact(contactName, geoDescription, imageUrl);
+ LogUtil.sanitizePii(geolocation),
+ photoUri);
+ return CequintCallerIdContact.builder()
+ .setName(contactName)
+ .setGeolocation(geolocation)
+ .setPhotoUri(photoUri)
+ .build();
} else {
LogUtil.d("CequintCallerIdManager.lookup", "No CequintCallerIdContact found");
return null;
@@ -249,8 +271,8 @@ public class CequintCallerIdManager {
return null;
}
- /** Returns geo location information. e.g. Mountain View, CA. */
- private static String getGeoDescription(
+ /** Returns geolocation information (e.g., "Mountain View, CA"). */
+ private static String getGeolocation(
String city, String state, String stateAbbr, String country) {
String geoDescription = null;
diff --git a/java/com/android/dialer/phonelookup/PhoneLookupModule.java b/java/com/android/dialer/phonelookup/PhoneLookupModule.java
index 86e6991c1..c6e91c4a4 100644
--- a/java/com/android/dialer/phonelookup/PhoneLookupModule.java
+++ b/java/com/android/dialer/phonelookup/PhoneLookupModule.java
@@ -17,6 +17,7 @@
package com.android.dialer.phonelookup;
import com.android.dialer.phonelookup.blockednumber.SystemBlockedNumberPhoneLookup;
+import com.android.dialer.phonelookup.cequint.CequintPhoneLookup;
import com.android.dialer.phonelookup.cnap.CnapPhoneLookup;
import com.android.dialer.phonelookup.cp2.Cp2DefaultDirectoryPhoneLookup;
import com.android.dialer.phonelookup.cp2.Cp2ExtendedDirectoryPhoneLookup;
@@ -32,12 +33,14 @@ public abstract class PhoneLookupModule {
@Provides
@SuppressWarnings({"unchecked", "rawtype"})
static ImmutableList<PhoneLookup> providePhoneLookupList(
+ CequintPhoneLookup cequintPhoneLookup,
CnapPhoneLookup cnapPhoneLookup,
Cp2DefaultDirectoryPhoneLookup cp2DefaultDirectoryPhoneLookup,
Cp2ExtendedDirectoryPhoneLookup cp2ExtendedDirectoryPhoneLookup,
SystemBlockedNumberPhoneLookup systemBlockedNumberPhoneLookup,
SpamPhoneLookup spamPhoneLookup) {
return ImmutableList.of(
+ cequintPhoneLookup,
cnapPhoneLookup,
cp2DefaultDirectoryPhoneLookup,
cp2ExtendedDirectoryPhoneLookup,
diff --git a/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java b/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java
new file mode 100644
index 000000000..ce2cd18ad
--- /dev/null
+++ b/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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.phonelookup.cequint;
+
+import android.content.Context;
+import android.telecom.Call;
+import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.phonelookup.PhoneLookup;
+import com.android.dialer.phonelookup.PhoneLookupInfo;
+import com.android.dialer.phonelookup.PhoneLookupInfo.CequintInfo;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import javax.inject.Inject;
+
+/** PhoneLookup implementation for Cequint. */
+public class CequintPhoneLookup implements PhoneLookup<CequintInfo> {
+
+ @Inject
+ CequintPhoneLookup() {}
+
+ @Override
+ public ListenableFuture<CequintInfo> lookup(Context appContext, Call call) {
+ // TODO(a bug): Override the default implementation in the PhoneLookup interface
+ // as a Cequint lookup requires info in the provided call.
+ return Futures.immediateFuture(CequintInfo.getDefaultInstance());
+ }
+
+ @Override
+ public ListenableFuture<CequintInfo> lookup(DialerPhoneNumber dialerPhoneNumber) {
+ // TODO(a bug): Implement this method.
+ return Futures.immediateFuture(CequintInfo.getDefaultInstance());
+ }
+
+ @Override
+ public ListenableFuture<Boolean> isDirty(ImmutableSet<DialerPhoneNumber> phoneNumbers) {
+ return Futures.immediateFuture(false);
+ }
+
+ @Override
+ public ListenableFuture<ImmutableMap<DialerPhoneNumber, CequintInfo>> getMostRecentInfo(
+ ImmutableMap<DialerPhoneNumber, CequintInfo> existingInfoMap) {
+ return Futures.immediateFuture(existingInfoMap);
+ }
+
+ @Override
+ public void setSubMessage(PhoneLookupInfo.Builder destination, CequintInfo subMessage) {
+ destination.setCequintInfo(subMessage);
+ }
+
+ @Override
+ public CequintInfo getSubMessage(PhoneLookupInfo phoneLookupInfo) {
+ return phoneLookupInfo.getCequintInfo();
+ }
+
+ @Override
+ public ListenableFuture<Void> onSuccessfulBulkUpdate() {
+ return Futures.immediateFuture(null);
+ }
+
+ @Override
+ public void registerContentObservers() {
+ // No content observers for Cequint info.
+ }
+
+ @Override
+ public void unregisterContentObservers() {
+ // No content observers for Cequint info.
+ }
+
+ @Override
+ public ListenableFuture<Void> clearData() {
+ return Futures.immediateFuture(null);
+ }
+}
diff --git a/java/com/android/dialer/phonelookup/phone_lookup_info.proto b/java/com/android/dialer/phonelookup/phone_lookup_info.proto
index 1beff6ca9..50817c4e3 100644
--- a/java/com/android/dialer/phonelookup/phone_lookup_info.proto
+++ b/java/com/android/dialer/phonelookup/phone_lookup_info.proto
@@ -14,7 +14,7 @@ package com.android.dialer.phonelookup;
// "cp2_info_in_default_directory" corresponds to class
// Cp2DefaultDirectoryPhoneLookup, and class Cp2DefaultDirectoryPhoneLookup
// alone is responsible for populating it.
-// Next ID: 8
+// Next ID: 9
message PhoneLookupInfo {
// Information about a PhoneNumber retrieved from CP2.
message Cp2Info {
@@ -163,4 +163,16 @@ message PhoneLookupInfo {
optional string name = 1;
}
optional CnapInfo cnap_info = 7;
+
+ // Information obtained via Cequint
+ // Next ID: 4
+ message CequintInfo {
+ optional string name = 1;
+
+ // Description of the geolocation (e.g., "Mountain View, CA")
+ optional string geolocation = 2;
+
+ optional string photo_uri = 3;
+ }
+ optional CequintInfo cequint_info = 8;
} \ No newline at end of file
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index 777175e00..4302436a7 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -625,16 +625,16 @@ public class ContactInfoHelper {
if (cequintCallerIdContact == null) {
return;
}
- if (TextUtils.isEmpty(info.name) && !TextUtils.isEmpty(cequintCallerIdContact.name)) {
- info.name = cequintCallerIdContact.name;
+ if (TextUtils.isEmpty(info.name) && !TextUtils.isEmpty(cequintCallerIdContact.name())) {
+ info.name = cequintCallerIdContact.name();
}
- if (!TextUtils.isEmpty(cequintCallerIdContact.geoDescription)) {
- info.geoDescription = cequintCallerIdContact.geoDescription;
+ if (!TextUtils.isEmpty(cequintCallerIdContact.geolocation())) {
+ info.geoDescription = cequintCallerIdContact.geolocation();
info.sourceType = ContactSource.Type.SOURCE_TYPE_CEQUINT_CALLER_ID;
}
// Only update photo if local lookup has no result.
- if (!info.contactExists && info.photoUri == null && cequintCallerIdContact.imageUrl != null) {
- info.photoUri = UriUtils.parseUriOrNull(cequintCallerIdContact.imageUrl);
+ if (!info.contactExists && info.photoUri == null && cequintCallerIdContact.photoUri() != null) {
+ info.photoUri = UriUtils.parseUriOrNull(cequintCallerIdContact.photoUri());
}
}
}
diff --git a/java/com/android/dialer/precall/impl/CallingAccountSelector.java b/java/com/android/dialer/precall/impl/CallingAccountSelector.java
index 16e7641ba..8f63fa0db 100644
--- a/java/com/android/dialer/precall/impl/CallingAccountSelector.java
+++ b/java/com/android/dialer/precall/impl/CallingAccountSelector.java
@@ -28,12 +28,15 @@ import android.telecom.TelecomManager;
import android.telephony.PhoneNumberUtils;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment.SelectPhoneAccountListener;
+import com.android.contacts.common.widget.SelectPhoneAccountDialogOptions;
+import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil;
+import com.android.dialer.activecalls.ActiveCallInfo;
+import com.android.dialer.activecalls.ActiveCallsComponent;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.DialerImpression.Type;
import com.android.dialer.logging.Logger;
import com.android.dialer.precall.PreCallAction;
@@ -41,10 +44,13 @@ import com.android.dialer.precall.PreCallCoordinator;
import com.android.dialer.precall.PreCallCoordinator.PendingAction;
import com.android.dialer.preferredsim.PreferredAccountRecorder;
import com.android.dialer.preferredsim.PreferredAccountWorker;
+import com.android.dialer.preferredsim.PreferredAccountWorker.Result;
import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
import com.android.dialer.preferredsim.suggestion.SuggestionProvider.Suggestion;
-import com.android.dialer.telecom.TelecomUtil;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
import java.util.List;
+import java.util.Objects;
/** PreCallAction to select which phone account to call with. Ignored if there's only one account */
@SuppressWarnings("MissingPermission")
@@ -75,17 +81,6 @@ public class CallingAccountSelector implements PreCallAction {
if (accounts.size() <= 1) {
return false;
}
-
- if (TelecomUtil.isInManagedCall(context)) {
- // Most devices are DSDS (dual SIM dual standby) which only one SIM can have active calls at
- // a time. Telecom will ignore the phone account handle and use the current active SIM, thus
- // there's no point of selecting SIMs
- // TODO(a bug): let the user know selections are not available and preferred SIM is not
- // used
- // TODO(twyen): support other dual SIM modes when the API is exposed.
- return false;
- }
-
return true;
}
@@ -134,12 +129,7 @@ public class CallingAccountSelector implements PreCallAction {
return;
}
if (result.getPhoneAccountHandle().isPresent()) {
- Logger.get(coordinator.getActivity())
- .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_PREFERRED_USED);
- coordinator
- .getBuilder()
- .setPhoneAccountHandle(result.getPhoneAccountHandle().get());
- pendingAction.finish();
+ usePreferredAccount(coordinator, pendingAction, result);
return;
}
PhoneAccountHandle defaultPhoneAccount =
@@ -147,10 +137,7 @@ public class CallingAccountSelector implements PreCallAction {
.getSystemService(TelecomManager.class)
.getDefaultOutgoingPhoneAccount(builder.getUri().getScheme());
if (defaultPhoneAccount != null) {
- Logger.get(coordinator.getActivity())
- .logImpression(DialerImpression.Type.DUAL_SIM_SELECTION_GLOBAL_USED);
- builder.setPhoneAccountHandle(defaultPhoneAccount);
- pendingAction.finish();
+ useDefaultAccount(coordinator, pendingAction, result, defaultPhoneAccount);
return;
}
if (result.getSuggestion().isPresent()) {
@@ -158,18 +145,7 @@ public class CallingAccountSelector implements PreCallAction {
"CallingAccountSelector.processPreferredAccount",
"SIM suggested: " + result.getSuggestion().get().reason);
if (result.getSuggestion().get().shouldAutoSelect) {
- Logger.get(coordinator.getActivity())
- .logImpression(
- DialerImpression.Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
- LogUtil.i(
- "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
- builder.setPhoneAccountHandle(result.getSuggestion().get().phoneAccountHandle);
- builder
- .getInCallUiIntentExtras()
- .putString(
- SuggestionProvider.EXTRA_SIM_SUGGESTION_REASON,
- result.getSuggestion().get().reason.name());
- pendingAction.finish();
+ useSuggestedAccount(coordinator, pendingAction, result);
return;
}
}
@@ -184,6 +160,120 @@ public class CallingAccountSelector implements PreCallAction {
.executeParallel(activity);
}
+ private void usePreferredAccount(
+ PreCallCoordinator coordinator, PendingAction pendingAction, Result result) {
+ String phoneNumber = coordinator.getBuilder().getUri().getSchemeSpecificPart();
+ if (isSelectable(coordinator.getActivity(), result.getPhoneAccountHandle().get())) {
+ Logger.get(coordinator.getActivity()).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
+ coordinator.getBuilder().setPhoneAccountHandle(result.getPhoneAccountHandle().get());
+ pendingAction.finish();
+ } else {
+ Logger.get(coordinator.getActivity())
+ .logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_NOT_SELECTABLE);
+ LogUtil.i("CallingAccountSelector.usePreferredAccount", "preferred account not selectable");
+ showDialog(
+ coordinator,
+ pendingAction,
+ result.getDataId().orNull(),
+ phoneNumber,
+ result.getSuggestion().orNull());
+ }
+ }
+
+ private void useDefaultAccount(
+ PreCallCoordinator coordinator,
+ PendingAction pendingAction,
+ Result result,
+ PhoneAccountHandle defaultPhoneAccount) {
+ CallIntentBuilder builder = coordinator.getBuilder();
+ String phoneNumber = builder.getUri().getSchemeSpecificPart();
+ if (isSelectable(coordinator.getActivity(), defaultPhoneAccount)) {
+ Logger.get(coordinator.getActivity()).logImpression(Type.DUAL_SIM_SELECTION_GLOBAL_USED);
+ builder.setPhoneAccountHandle(defaultPhoneAccount);
+ pendingAction.finish();
+ } else {
+ Logger.get(coordinator.getActivity())
+ .logImpression(Type.DUAL_SIM_SELECTION_GLOBAL_NOT_SELECTABLE);
+ LogUtil.i("CallingAccountSelector.useDefaultAccount", "default account not selectable");
+ showDialog(
+ coordinator,
+ pendingAction,
+ result.getDataId().orNull(),
+ phoneNumber,
+ result.getSuggestion().orNull());
+ }
+ }
+
+ private void useSuggestedAccount(
+ PreCallCoordinator coordinator, PendingAction pendingAction, Result result) {
+ CallIntentBuilder builder = coordinator.getBuilder();
+ String phoneNumber = builder.getUri().getSchemeSpecificPart();
+ if (isSelectable(coordinator.getActivity(), result.getSuggestion().get().phoneAccountHandle)) {
+ Logger.get(coordinator.getActivity())
+ .logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
+ LogUtil.i("CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
+ builder.setPhoneAccountHandle(result.getSuggestion().get().phoneAccountHandle);
+ builder
+ .getInCallUiIntentExtras()
+ .putString(
+ SuggestionProvider.EXTRA_SIM_SUGGESTION_REASON,
+ result.getSuggestion().get().reason.name());
+ pendingAction.finish();
+ } else {
+ LogUtil.i("CallingAccountSelector.useSuggestedAccount", "suggested account not selectable");
+ Logger.get(coordinator.getActivity())
+ .logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_NOT_SELECTABLE);
+ showDialog(
+ coordinator,
+ pendingAction,
+ result.getDataId().orNull(),
+ phoneNumber,
+ result.getSuggestion().orNull());
+ }
+ }
+
+ /**
+ * Most devices are DSDS (dual SIM dual standby) which only one SIM can have active calls at a
+ * time. TODO(twyen): support other dual SIM modes when the API is exposed.
+ */
+ private static boolean isSelectable(Context context, PhoneAccountHandle phoneAccountHandle) {
+ ImmutableList<ActiveCallInfo> activeCalls =
+ ActiveCallsComponent.get(context).activeCalls().getActiveCalls();
+ if (activeCalls.isEmpty()) {
+ return true;
+ }
+ for (ActiveCallInfo activeCall : activeCalls) {
+ if (Objects.equals(phoneAccountHandle, activeCall.phoneAccountHandle().orNull())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static Optional<String> getActiveCallLabel(Context context) {
+ ImmutableList<ActiveCallInfo> activeCalls =
+ ActiveCallsComponent.get(context).activeCalls().getActiveCalls();
+
+ if (activeCalls.isEmpty()) {
+ LogUtil.e("CallingAccountSelector.getActiveCallLabel", "active calls no longer exist");
+ return Optional.absent();
+ }
+ ActiveCallInfo activeCall = activeCalls.get(0);
+ if (!activeCall.phoneAccountHandle().isPresent()) {
+ LogUtil.e("CallingAccountSelector.getActiveCallLabel", "active call has no phone account");
+ return Optional.absent();
+ }
+ PhoneAccount phoneAccount =
+ context
+ .getSystemService(TelecomManager.class)
+ .getPhoneAccount(activeCall.phoneAccountHandle().get());
+ if (phoneAccount == null) {
+ LogUtil.e("CallingAccountSelector.getActiveCallLabel", "phone account not found");
+ return Optional.absent();
+ }
+ return Optional.of(phoneAccount.getLabel().toString());
+ }
+
@MainThread
private void showDialog(
PreCallCoordinator coordinator,
@@ -211,24 +301,47 @@ public class CallingAccountSelector implements PreCallAction {
default:
}
}
- List<PhoneAccountHandle> phoneAccountHandles =
+ SelectPhoneAccountDialogOptions.Builder optionsBuilder =
+ SelectPhoneAccountDialogOptions.newBuilder()
+ .setTitle(R.string.pre_call_select_phone_account)
+ .setCanSetDefault(dataId != null)
+ .setSetDefaultLabel(R.string.pre_call_select_phone_account_remember);
+
+ for (PhoneAccountHandle phoneAccountHandle :
coordinator
.getActivity()
.getSystemService(TelecomManager.class)
- .getCallCapablePhoneAccounts();
+ .getCallCapablePhoneAccounts()) {
+ SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder =
+ SelectPhoneAccountDialogOptions.Entry.newBuilder();
+ SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle(entryBuilder, phoneAccountHandle);
+ if (isSelectable(coordinator.getActivity(), phoneAccountHandle)) {
+ Optional<String> hint =
+ SuggestionProvider.getHint(coordinator.getActivity(), phoneAccountHandle, suggestion);
+ if (hint.isPresent()) {
+ entryBuilder.setHint(hint.get());
+ }
+ } else {
+ entryBuilder.setEnabled(false);
+ Optional<String> activeCallLabel = getActiveCallLabel(coordinator.getActivity());
+ if (activeCallLabel.isPresent()) {
+ entryBuilder.setHint(
+ coordinator
+ .getActivity()
+ .getString(
+ R.string.pre_call_select_phone_account_hint_other_sim_in_use,
+ activeCallLabel.get()));
+ }
+ }
+ optionsBuilder.addEntries(entryBuilder);
+ }
selectPhoneAccountDialogFragment =
SelectPhoneAccountDialogFragment.newInstance(
- R.string.pre_call_select_phone_account,
- dataId != null /* canSetDefault */,
- R.string.pre_call_select_phone_account_remember,
- phoneAccountHandles,
+ optionsBuilder.build(),
new SelectedListener(
coordinator,
pendingAction,
- new PreferredAccountRecorder(number, suggestion, dataId)),
- null /* call ID */,
- SuggestionProvider.buildHint(
- coordinator.getActivity(), phoneAccountHandles, suggestion));
+ new PreferredAccountRecorder(number, suggestion, dataId)));
selectPhoneAccountDialogFragment.show(
coordinator.getActivity().getFragmentManager(), TAG_CALLING_ACCOUNT_SELECTOR);
}
diff --git a/java/com/android/dialer/precall/impl/res/values/strings.xml b/java/com/android/dialer/precall/impl/res/values/strings.xml
index 4bd5d36f2..5e7ddd36c 100644
--- a/java/com/android/dialer/precall/impl/res/values/strings.xml
+++ b/java/com/android/dialer/precall/impl/res/values/strings.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Toast when the user tried to place a call but has revoked phone permission [CHAR_LIMIT=none] -->
<string name="pre_call_permission_check_no_phone_permission">Cannot make call without phone permission</string>
@@ -26,4 +26,8 @@
same contact and never ask again [CHAR LIMIT=40]-->
<string name="pre_call_select_phone_account_remember">Remember this choice</string>
+ <!-- Hint to show under a SIM entry when selecting SIM for call on a multi-SIM device, when the
+ call cannot be placed with the SIM because there is already a call on the other SIM,
+ [CHAR LIMIT=NONE]-->
+ <string name="pre_call_select_phone_account_hint_other_sim_in_use">Not available while using <xliff:g example="SIM 1" id="other_sim">%1$s</xliff:g></string>
</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java b/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java
index f710f734c..50ae01fd0 100644
--- a/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java
+++ b/java/com/android/dialer/preferredsim/suggestion/SuggestionProvider.java
@@ -24,10 +24,9 @@ import android.telecom.PhoneAccountHandle;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.google.common.base.Optional;
-import java.util.ArrayList;
-import java.util.List;
/** Provides hints to the user when selecting a SIM to make a call. */
+@SuppressWarnings("Guava")
public interface SuggestionProvider {
String EXTRA_SIM_SUGGESTION_REASON = "sim_suggestion_reason";
@@ -80,35 +79,25 @@ public interface SuggestionProvider {
@NonNull Context context, @NonNull String number, @NonNull PhoneAccountHandle newAccount);
/**
- * Return a list of suggestion strings matching the list position of the {@code
- * phoneAccountHandles}. The list will contain {@code null} if the PhoneAccountHandle does not
- * have suggestions.
+ * Return the hint for {@code phoneAccountHandle}. Absent if no hint is available for the account.
*/
- @Nullable
- static List<String> buildHint(
- Context context,
- List<PhoneAccountHandle> phoneAccountHandles,
- @Nullable Suggestion suggestion) {
+ static Optional<String> getHint(
+ Context context, PhoneAccountHandle phoneAccountHandle, @Nullable Suggestion suggestion) {
if (suggestion == null) {
- return null;
+ return Optional.absent();
}
- List<String> hints = new ArrayList<>();
- for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
- if (!phoneAccountHandle.equals(suggestion.phoneAccountHandle)) {
- hints.add(null);
- continue;
- }
- switch (suggestion.reason) {
- case INTRA_CARRIER:
- hints.add(context.getString(R.string.pre_call_select_phone_account_hint_intra_carrier));
- break;
- case FREQUENT:
- hints.add(context.getString(R.string.pre_call_select_phone_account_hint_frequent));
- break;
- default:
- LogUtil.w("CallingAccountSelector.buildHint", "unhandled reason " + suggestion.reason);
- }
+ if (!phoneAccountHandle.equals(suggestion.phoneAccountHandle)) {
+ return Optional.absent();
+ }
+ switch (suggestion.reason) {
+ case INTRA_CARRIER:
+ return Optional.of(
+ context.getString(R.string.pre_call_select_phone_account_hint_intra_carrier));
+ case FREQUENT:
+ return Optional.of(context.getString(R.string.pre_call_select_phone_account_hint_frequent));
+ default:
+ LogUtil.w("CallingAccountSelector.getHint", "unhandled reason " + suggestion.reason);
+ return Optional.absent();
}
- return hints;
}
}
diff --git a/java/com/android/dialer/speeddial/SpeedDialAdapter.java b/java/com/android/dialer/speeddial/SpeedDialAdapter.java
index 6f6ac5498..8a37e97dd 100644
--- a/java/com/android/dialer/speeddial/SpeedDialAdapter.java
+++ b/java/com/android/dialer/speeddial/SpeedDialAdapter.java
@@ -210,4 +210,9 @@ public final class SpeedDialAdapter extends RecyclerView.Adapter<RecyclerView.Vi
public void setItemTouchHelper(ItemTouchHelper itemTouchHelper) {
this.itemTouchHelper = itemTouchHelper;
}
+
+ /** Returns true if there are suggested contacts. */
+ public boolean hasFrequents() {
+ return !speedDialUiItems.isEmpty() && getItemViewType(getItemCount() - 1) == RowType.SUGGESTION;
+ }
}
diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java
index 26893a8d3..b74c06239 100644
--- a/java/com/android/dialer/speeddial/SpeedDialFragment.java
+++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java
@@ -34,6 +34,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.common.concurrent.SupportUiListener;
@@ -132,11 +133,6 @@ public class SpeedDialFragment extends Fragment {
return rootLayout;
}
- public boolean hasFrequents() {
- // TODO(calderwoodra)
- return false;
- }
-
@Override
public void onResume() {
super.onResume();
@@ -173,12 +169,17 @@ public class SpeedDialFragment extends Fragment {
}
private void onSpeedDialUiItemListLoaded(ImmutableList<SpeedDialUiItem> speedDialUiItems) {
+ LogUtil.enterBlock("SpeedDialFragment.onSpeedDialUiItemListLoaded");
// TODO(calderwoodra): Use DiffUtil to properly update and animate the change
adapter.setSpeedDialUiItems(
UiItemLoaderComponent.get(getContext())
.speedDialUiItemLoader()
.insertDuoChannels(getContext(), speedDialUiItems));
adapter.notifyDataSetChanged();
+ if (getActivity() != null) {
+ FragmentUtils.getParentUnsafe(this, HostInterface.class)
+ .setHasFrequents(adapter.hasFrequents());
+ }
}
@Override
@@ -359,4 +360,10 @@ public class SpeedDialFragment extends Fragment {
Contacts.CONTENT_URI, String.valueOf(speedDialUiItem.contactId()))));
}
}
+
+ /** Interface for {@link SpeedDialFragment} to communicate with its host/parent. */
+ public interface HostInterface {
+
+ void setHasFrequents(boolean hasFrequents);
+ }
}
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java
index ce771c3c8..4d6ac2d7f 100644
--- a/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java
@@ -17,6 +17,7 @@
package com.android.dialer.speeddial.database;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
/**
* Interface that databases support speed dial entries should implement.
@@ -32,8 +33,10 @@ public interface SpeedDialEntryDao {
* Insert new entries.
*
* <p>{@link SpeedDialEntry#id() ids} must be null.
+ *
+ * @return a map of the inserted entries to their new ids.
*/
- void insert(ImmutableList<SpeedDialEntry> entries);
+ ImmutableMap<SpeedDialEntry, Long> insert(ImmutableList<SpeedDialEntry> entries);
/**
* Insert a new entry.
@@ -59,11 +62,12 @@ public interface SpeedDialEntryDao {
/**
* Inserts, updates and deletes rows all in on transaction.
*
+ * @return a map of the inserted entries to their new ids.
* @see #insert(ImmutableList)
* @see #update(ImmutableList)
* @see #delete(ImmutableList)
*/
- void insertUpdateAndDelete(
+ ImmutableMap<SpeedDialEntry, Long> insertUpdateAndDelete(
ImmutableList<SpeedDialEntry> entriesToInsert,
ImmutableList<SpeedDialEntry> entriesToUpdate,
ImmutableList<Long> entriesToDelete);
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
index 137933fbe..544bb3613 100644
--- a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
@@ -26,6 +26,7 @@ import com.android.dialer.common.Assert;
import com.android.dialer.common.database.Selection;
import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.List;
@@ -132,30 +133,39 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
}
@Override
- public void insert(ImmutableList<SpeedDialEntry> entries) {
+ public ImmutableMap<SpeedDialEntry, Long> insert(ImmutableList<SpeedDialEntry> entries) {
if (entries.isEmpty()) {
- return;
+ return ImmutableMap.of();
}
SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
- insert(db, entries);
+ ImmutableMap<SpeedDialEntry, Long> insertedEntriesToIdsMap = insert(db, entries);
db.setTransactionSuccessful();
+ return insertedEntriesToIdsMap;
} finally {
db.endTransaction();
db.close();
}
}
- private void insert(SQLiteDatabase writeableDatabase, ImmutableList<SpeedDialEntry> entries) {
+ private ImmutableMap<SpeedDialEntry, Long> insert(
+ SQLiteDatabase writeableDatabase, ImmutableList<SpeedDialEntry> entries) {
+ ImmutableMap.Builder<SpeedDialEntry, Long> insertedEntriesToIdsMap = ImmutableMap.builder();
for (SpeedDialEntry entry : entries) {
Assert.checkArgument(entry.id() == null);
- if (writeableDatabase.insert(TABLE_NAME, null, buildContentValuesWithoutId(entry)) == -1L) {
+ long id = writeableDatabase.insert(TABLE_NAME, null, buildContentValuesWithoutId(entry));
+ if (id == -1L) {
throw Assert.createUnsupportedOperationFailException(
"Attempted to insert a row that already exists.");
}
+ // It's impossible to insert two identical entries but this is an important assumption we need
+ // to verify because there's an assumption that each entry will correspond to exactly one id.
+ // ImmutableMap#put verifies this check for us.
+ insertedEntriesToIdsMap.put(entry, id);
}
+ return insertedEntriesToIdsMap.build();
}
@Override
@@ -255,20 +265,21 @@ public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
}
@Override
- public void insertUpdateAndDelete(
+ public ImmutableMap<SpeedDialEntry, Long> insertUpdateAndDelete(
ImmutableList<SpeedDialEntry> entriesToInsert,
ImmutableList<SpeedDialEntry> entriesToUpdate,
ImmutableList<Long> entriesToDelete) {
if (entriesToInsert.isEmpty() && entriesToUpdate.isEmpty() && entriesToDelete.isEmpty()) {
- return;
+ return ImmutableMap.of();
}
SQLiteDatabase db = getWritableDatabase();
db.beginTransaction();
try {
- insert(db, entriesToInsert);
+ ImmutableMap<SpeedDialEntry, Long> insertedEntriesToIdsMap = insert(db, entriesToInsert);
update(db, entriesToUpdate);
delete(db, entriesToDelete);
db.setTransactionSuccessful();
+ return insertedEntriesToIdsMap;
} finally {
db.endTransaction();
db.close();
diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
index 24bc776e7..9bda3fb31 100644
--- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
+++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
@@ -136,6 +136,15 @@ public abstract class SpeedDialUiItem {
return builder.build();
}
+ public SpeedDialEntry buildSpeedDialEntry() {
+ return SpeedDialEntry.builder()
+ .setId(speedDialEntryId())
+ .setLookupKey(lookupKey())
+ .setContactId(contactId())
+ .setDefaultChannel(defaultChannel())
+ .build();
+ }
+
/**
* Returns a video channel if there is exactly one video channel or the default channel is a video
* channel.
diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java
index 7107706fe..921468773 100644
--- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java
+++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItemLoader.java
@@ -44,6 +44,7 @@ import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
import com.android.dialer.speeddial.database.SpeedDialEntryDao;
import com.android.dialer.speeddial.database.SpeedDialEntryDatabaseHelper;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.util.ArrayList;
@@ -146,13 +147,7 @@ public final class SpeedDialUiItemLoader {
}
// Insert a new entry into the SpeedDialEntry database
- getSpeedDialEntryDao()
- .insert(
- SpeedDialEntry.builder()
- .setLookupKey(item.lookupKey())
- .setContactId(item.contactId())
- .setDefaultChannel(item.defaultChannel())
- .build());
+ getSpeedDialEntryDao().insert(item.buildSpeedDialEntry());
}
return loadSpeedDialUiItemsInternal();
}
@@ -216,23 +211,55 @@ public final class SpeedDialUiItemLoader {
contact.toBuilder().setDefaultChannel(contact.channels().get(0)).build());
} else if (speedDialUiItems.stream().noneMatch(c -> c.contactId() == contact.contactId())) {
- entriesToInsert.add(
- SpeedDialEntry.builder()
- .setLookupKey(contact.lookupKey())
- .setContactId(contact.contactId())
- .setDefaultChannel(contact.defaultChannel())
- .build());
+ entriesToInsert.add(contact.buildSpeedDialEntry());
// These are our newly starred contacts
speedDialUiItems.add(contact);
}
}
- db.insertUpdateAndDelete(
- ImmutableList.copyOf(entriesToInsert),
- ImmutableList.copyOf(entriesToUpdate),
- ImmutableList.copyOf(entriesToDelete));
- return ImmutableList.copyOf(speedDialUiItems);
+ ImmutableMap<SpeedDialEntry, Long> insertedEntriesToIdsMap =
+ db.insertUpdateAndDelete(
+ ImmutableList.copyOf(entriesToInsert),
+ ImmutableList.copyOf(entriesToUpdate),
+ ImmutableList.copyOf(entriesToDelete));
+ return speedDialUiItemsWithUpdatedIds(speedDialUiItems, insertedEntriesToIdsMap);
+ }
+
+ /**
+ * Since newly starred contacts sometimes aren't in the SpeedDialEntry database, we couldn't set
+ * their ids when we created our initial list of {@link SpeedDialUiItem speedDialUiItems}. Now
+ * that we've inserted the entries into the database and we have their ids, build a new list of
+ * speedDialUiItems with the now known ids.
+ */
+ private ImmutableList<SpeedDialUiItem> speedDialUiItemsWithUpdatedIds(
+ List<SpeedDialUiItem> speedDialUiItems,
+ ImmutableMap<SpeedDialEntry, Long> insertedEntriesToIdsMap) {
+ if (insertedEntriesToIdsMap.isEmpty()) {
+ // There were no newly inserted entries, so all entries ids are set already.
+ return ImmutableList.copyOf(speedDialUiItems);
+ }
+
+ ImmutableList.Builder<SpeedDialUiItem> updatedItems = ImmutableList.builder();
+ for (SpeedDialUiItem speedDialUiItem : speedDialUiItems) {
+ SpeedDialEntry entry = speedDialUiItem.buildSpeedDialEntry();
+ if (insertedEntriesToIdsMap.containsKey(entry)) {
+ // Get the id for newly inserted entry, update our SpeedDialUiItem and add it to our list
+ Long id = Assert.isNotNull(insertedEntriesToIdsMap.get(entry));
+ updatedItems.add(speedDialUiItem.toBuilder().setSpeedDialEntryId(id).build());
+ continue;
+ }
+
+ // Starred contacts that aren't in the map, should already have speed dial entry ids.
+ // Non-starred contacts (suggestions) aren't in the speed dial entry database, so they
+ // shouldn't have speed dial entry ids.
+ Assert.checkArgument(
+ speedDialUiItem.isStarred() == (speedDialUiItem.speedDialEntryId() != null),
+ "Contact must be starred with a speed dial entry id, or not starred with no id "
+ + "(suggested contacts)");
+ updatedItems.add(speedDialUiItem);
+ }
+ return updatedItems.build();
}
/**
diff --git a/java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml b/java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml
new file mode 100644
index 000000000..347db41bc
--- /dev/null
+++ b/java/com/android/dialer/theme/res/color/dialer_primary_text_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 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
+ -->
+<!-- Primary text color in the Phone app -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/dialer_disabled_text_color"/>
+ <item android:color="#212121"/>
+</selector> \ No newline at end of file
diff --git a/java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml b/java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml
new file mode 100644
index 000000000..920b46792
--- /dev/null
+++ b/java/com/android/dialer/theme/res/color/dialer_secondary_text_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 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
+ -->
+<!-- Secondary text color in the Phone app -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/dialer_disabled_text_color"/>
+ <item android:color="#636363"/>
+</selector> \ No newline at end of file
diff --git a/java/com/android/dialer/theme/res/values/colors.xml b/java/com/android/dialer/theme/res/values/colors.xml
index e80fc4b30..2185d861c 100644
--- a/java/com/android/dialer/theme/res/values/colors.xml
+++ b/java/com/android/dialer/theme/res/values/colors.xml
@@ -36,15 +36,11 @@
<color name="dialer_secondary_color">#F50057</color>
- <!-- Primary text color in the Phone app -->
- <color name="dialer_primary_text_color">#333333</color>
<color name="dialer_primary_text_color_white">#ffffff</color>
<color name="dialer_edit_text_hint_color">#DE78909C</color>
- <!-- Secondary text color in the Phone app -->
- <color name="dialer_secondary_text_color">#636363</color>
<!-- 38% opacity -->
- <color name="dialer_secondary_text_color_hiden">#61000000</color>
+ <color name="dialer_disabled_text_color">#9E9E9E</color>
<color name="dialer_link_color">#2A56C6</color>
diff --git a/java/com/android/incallui/ActiveCallsCallListListener.java b/java/com/android/incallui/ActiveCallsCallListListener.java
new file mode 100644
index 000000000..ce9f9a36d
--- /dev/null
+++ b/java/com/android/incallui/ActiveCallsCallListListener.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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.incallui;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import com.android.dialer.activecalls.ActiveCallInfo;
+import com.android.dialer.activecalls.ActiveCallsComponent;
+import com.android.incallui.call.CallList;
+import com.android.incallui.call.DialerCall;
+import com.android.incallui.call.DialerCall.State;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+
+/** Updates {@link com.android.dialer.activecalls.ActiveCalls} */
+@SuppressWarnings("Guava")
+public class ActiveCallsCallListListener implements CallList.Listener {
+
+ private final Context appContext;
+
+ ActiveCallsCallListListener(Context appContext) {
+ this.appContext = appContext;
+ }
+
+ @Override
+ public void onIncomingCall(DialerCall call) {}
+
+ @Override
+ public void onUpgradeToVideo(DialerCall call) {}
+
+ @Override
+ public void onSessionModificationStateChange(DialerCall call) {}
+
+ @Override
+ public void onCallListChange(CallList callList) {
+ ImmutableList.Builder<ActiveCallInfo> activeCalls = ImmutableList.builder();
+ for (DialerCall call : callList.getAllCalls()) {
+ if (call.getState() != State.DISCONNECTED) {
+ activeCalls.add(
+ ActiveCallInfo.builder()
+ .setPhoneAccountHandle(Optional.fromNullable(call.getAccountHandle()))
+ .build());
+ }
+ }
+ ActiveCallsComponent.get(appContext).activeCalls().setActiveCalls(activeCalls.build());
+ }
+
+ @Override
+ public void onDisconnect(DialerCall call) {}
+
+ @Override
+ public void onWiFiToLteHandover(DialerCall call) {}
+
+ @Override
+ public void onHandoverToWifiFailed(DialerCall call) {}
+
+ @Override
+ public void onInternationalCallOnWifi(@NonNull DialerCall call) {}
+}
diff --git a/java/com/android/incallui/ConferenceParticipantListAdapter.java b/java/com/android/incallui/ConferenceParticipantListAdapter.java
index 4780974ef..dc793f7f8 100644
--- a/java/com/android/incallui/ConferenceParticipantListAdapter.java
+++ b/java/com/android/incallui/ConferenceParticipantListAdapter.java
@@ -356,7 +356,7 @@ public class ConferenceParticipantListAdapter extends BaseAdapter {
statusTextView.setText(onHoldText);
statusTextView.setVisibility(View.VISIBLE);
- int onHoldColor = getContext().getColor(R.color.dialer_secondary_text_color_hiden);
+ int onHoldColor = getContext().getColor(R.color.dialer_disabled_text_color);
nameTextView.setTextColor(onHoldColor);
numberTextView.setTextColor(onHoldColor);
diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java
index 165ec13bf..eefd4833c 100644
--- a/java/com/android/incallui/ContactInfoCache.java
+++ b/java/com/android/incallui/ContactInfoCache.java
@@ -522,20 +522,20 @@ public class ContactInfoCache implements OnImageLoadCompleteListener {
}
boolean hasUpdate = false;
- if (TextUtils.isEmpty(callerInfo.name) && !TextUtils.isEmpty(cequintCallerIdContact.name)) {
- callerInfo.name = cequintCallerIdContact.name;
+ if (TextUtils.isEmpty(callerInfo.name) && !TextUtils.isEmpty(cequintCallerIdContact.name())) {
+ callerInfo.name = cequintCallerIdContact.name();
hasUpdate = true;
}
- if (!TextUtils.isEmpty(cequintCallerIdContact.geoDescription)) {
- callerInfo.geoDescription = cequintCallerIdContact.geoDescription;
+ if (!TextUtils.isEmpty(cequintCallerIdContact.geolocation())) {
+ callerInfo.geoDescription = cequintCallerIdContact.geolocation();
callerInfo.shouldShowGeoDescription = true;
hasUpdate = true;
}
// Don't overwrite photo in local contacts.
if (!callerInfo.contactExists
&& callerInfo.contactDisplayPhotoUri == null
- && cequintCallerIdContact.imageUrl != null) {
- callerInfo.contactDisplayPhotoUri = Uri.parse(cequintCallerIdContact.imageUrl);
+ && cequintCallerIdContact.photoUri() != null) {
+ callerInfo.contactDisplayPhotoUri = Uri.parse(cequintCallerIdContact.photoUri());
hasUpdate = true;
}
// Set contact to exist to avoid phone number service lookup.
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 91f557bd5..2b6c2b49d 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -55,12 +55,15 @@ import android.view.animation.AnimationUtils;
import android.widget.CheckBox;
import android.widget.Toast;
import com.android.contacts.common.widget.SelectPhoneAccountDialogFragment;
+import com.android.contacts.common.widget.SelectPhoneAccountDialogOptions;
+import com.android.contacts.common.widget.SelectPhoneAccountDialogOptionsUtil;
import com.android.dialer.animation.AnimUtils;
import com.android.dialer.animation.AnimationListenerAdapter;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.dialer.common.concurrent.UiListener;
import com.android.dialer.configprovider.ConfigProviderBindings;
import com.android.dialer.logging.DialerImpression.Type;
import com.android.dialer.logging.Logger;
@@ -69,6 +72,7 @@ import com.android.dialer.metrics.Metrics;
import com.android.dialer.metrics.MetricsComponent;
import com.android.dialer.preferredsim.PreferredAccountRecorder;
import com.android.dialer.preferredsim.PreferredAccountWorker;
+import com.android.dialer.preferredsim.PreferredAccountWorker.Result;
import com.android.dialer.preferredsim.suggestion.SuggestionProvider;
import com.android.dialer.util.ViewUtil;
import com.android.incallui.answer.bindings.AnswerBindings;
@@ -101,6 +105,7 @@ import com.android.incallui.video.protocol.VideoCallScreen;
import com.android.incallui.video.protocol.VideoCallScreenDelegate;
import com.android.incallui.video.protocol.VideoCallScreenDelegateFactory;
import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -129,10 +134,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity
private static Optional<Integer> audioRouteForTesting = Optional.absent();
- private final InternationalCallOnWifiCallback internationalCallOnWifiCallback =
- new InternationalCallOnWifiCallback();
-
private SelectPhoneAccountListener selectPhoneAccountListener;
+ private UiListener<Result> preferredAccountWorkerResultListener;
private Animation dialpadSlideInAnimation;
private Animation dialpadSlideOutAnimation;
@@ -189,6 +192,10 @@ public class InCallActivity extends TransactionSafeFragmentActivity
Trace.beginSection("InCallActivity.onCreate");
super.onCreate(bundle);
+ preferredAccountWorkerResultListener =
+ DialerExecutorComponent.get(this)
+ .createUiListener(getFragmentManager(), "preferredAccountWorkerResultListener");
+
selectPhoneAccountListener = new SelectPhoneAccountListener(getApplicationContext());
if (bundle != null) {
@@ -245,13 +252,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity
}
}
- InternationalCallOnWifiDialogFragment existingInternationalCallOnWifiDialogFragment =
- (InternationalCallOnWifiDialogFragment)
- getSupportFragmentManager().findFragmentByTag(Tags.INTERNATIONAL_CALL_ON_WIFI);
- if (existingInternationalCallOnWifiDialogFragment != null) {
- existingInternationalCallOnWifiDialogFragment.setCallback(internationalCallOnWifiCallback);
- }
-
inCallOrientationEventListener = new InCallOrientationEventListener(this);
getWindow()
@@ -368,58 +368,84 @@ public class InCallActivity extends TransactionSafeFragmentActivity
return false;
}
- DialerExecutorComponent.get(this)
- .dialerExecutorFactory()
- .createNonUiTaskBuilder(new PreferredAccountWorker(waitingForAccountCall.getNumber()))
- .onSuccess(
- (result -> {
- if (result.getPhoneAccountHandle().isPresent()) {
- Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
- selectPhoneAccountListener.onPhoneAccountSelected(
- result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
- return;
- }
- if (result.getSuggestion().isPresent()) {
- LogUtil.i(
- "CallingAccountSelector.processPreferredAccount",
- "SIM suggested: " + result.getSuggestion().get().reason);
- if (result.getSuggestion().get().shouldAutoSelect) {
- Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
- LogUtil.i(
- "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
- selectPhoneAccountListener.onPhoneAccountSelected(
- result.getSuggestion().get().phoneAccountHandle,
- false,
- waitingForAccountCall.getId());
- return;
- }
- }
- Bundle extras = waitingForAccountCall.getIntentExtras();
- List<PhoneAccountHandle> phoneAccountHandles =
- extras == null
- ? new ArrayList<>()
- : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
-
- waitingForAccountCall.setPreferredAccountRecorder(
- new PreferredAccountRecorder(
- waitingForAccountCall.getNumber(),
- result.getSuggestion().orNull(),
- result.getDataId().orNull()));
- selectPhoneAccountDialogFragment =
- SelectPhoneAccountDialogFragment.newInstance(
- R.string.select_phone_account_for_calls,
- result.getDataId().isPresent() /* canSetDefault */,
- R.string.select_phone_account_for_calls_remember /* setDefaultResId */,
- phoneAccountHandles,
- selectPhoneAccountListener,
- waitingForAccountCall.getId(),
- SuggestionProvider.buildHint(
- this, phoneAccountHandles, result.getSuggestion().orNull() /* hints */));
- selectPhoneAccountDialogFragment.show(
- getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
- }))
- .build()
- .executeParallel(this);
+ ListenableFuture<PreferredAccountWorker.Result> preferredAccountFuture =
+ DialerExecutorComponent.get(this)
+ .backgroundExecutor()
+ .submit(
+ () -> {
+ try {
+ return new PreferredAccountWorker(waitingForAccountCall.getNumber())
+ .doInBackground(getApplicationContext());
+ } catch (Throwable throwable) {
+ throw new Exception(throwable);
+ }
+ });
+
+ preferredAccountWorkerResultListener.listen(
+ this,
+ preferredAccountFuture,
+ result -> {
+ if (result.getPhoneAccountHandle().isPresent()) {
+ Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_PREFERRED_USED);
+ selectPhoneAccountListener.onPhoneAccountSelected(
+ result.getPhoneAccountHandle().get(), false, waitingForAccountCall.getId());
+ return;
+ }
+ if (result.getSuggestion().isPresent()) {
+ LogUtil.i(
+ "CallingAccountSelector.processPreferredAccount",
+ "SIM suggested: " + result.getSuggestion().get().reason);
+ if (result.getSuggestion().get().shouldAutoSelect) {
+ Logger.get(this).logImpression(Type.DUAL_SIM_SELECTION_SUGGESTION_AUTO_SELECTED);
+ LogUtil.i(
+ "CallingAccountSelector.processPreferredAccount", "Auto selected suggestion");
+ selectPhoneAccountListener.onPhoneAccountSelected(
+ result.getSuggestion().get().phoneAccountHandle,
+ false,
+ waitingForAccountCall.getId());
+ return;
+ }
+ }
+ Bundle extras = waitingForAccountCall.getIntentExtras();
+ List<PhoneAccountHandle> phoneAccountHandles =
+ extras == null
+ ? new ArrayList<>()
+ : extras.getParcelableArrayList(Call.AVAILABLE_PHONE_ACCOUNTS);
+
+ waitingForAccountCall.setPreferredAccountRecorder(
+ new PreferredAccountRecorder(
+ waitingForAccountCall.getNumber(),
+ result.getSuggestion().orNull(),
+ result.getDataId().orNull()));
+ SelectPhoneAccountDialogOptions.Builder optionsBuilder =
+ SelectPhoneAccountDialogOptions.newBuilder()
+ .setTitle(R.string.select_phone_account_for_calls)
+ .setCanSetDefault(result.getDataId().isPresent())
+ .setSetDefaultLabel(R.string.select_phone_account_for_calls_remember)
+ .setCallId(waitingForAccountCall.getId());
+
+ for (PhoneAccountHandle phoneAccountHandle : phoneAccountHandles) {
+ SelectPhoneAccountDialogOptions.Entry.Builder entryBuilder =
+ SelectPhoneAccountDialogOptions.Entry.newBuilder();
+ SelectPhoneAccountDialogOptionsUtil.setPhoneAccountHandle(
+ entryBuilder, phoneAccountHandle);
+ Optional<String> hint =
+ SuggestionProvider.getHint(
+ this, phoneAccountHandle, result.getSuggestion().orNull());
+ if (hint.isPresent()) {
+ entryBuilder.setHint(hint.get());
+ }
+ optionsBuilder.addEntries(entryBuilder);
+ }
+
+ selectPhoneAccountDialogFragment =
+ SelectPhoneAccountDialogFragment.newInstance(
+ optionsBuilder.build(), selectPhoneAccountListener);
+ selectPhoneAccountDialogFragment.show(getFragmentManager(), Tags.SELECT_ACCOUNT_FRAGMENT);
+ },
+ throwable -> {
+ throw new RuntimeException(throwable);
+ });
return true;
}
@@ -1201,16 +1227,8 @@ public class InCallActivity extends TransactionSafeFragmentActivity
}
public void showDialogForInternationalCallOnWifi(@NonNull DialerCall call) {
- if (!InternationalCallOnWifiDialogFragment.shouldShow(this)) {
- LogUtil.i(
- "InCallActivity.showDialogForInternationalCallOnWifi",
- "InternationalCallOnWifiDialogFragment.shouldShow returned false");
- return;
- }
-
InternationalCallOnWifiDialogFragment fragment =
- InternationalCallOnWifiDialogFragment.newInstance(
- call.getId(), internationalCallOnWifiCallback);
+ InternationalCallOnWifiDialogFragment.newInstance(call.getId());
fragment.show(getSupportFragmentManager(), Tags.INTERNATIONAL_CALL_ON_WIFI);
}
@@ -1785,28 +1803,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity
static final String ANSWER_AND_RELEASE_ENABLED = "answer_and_release_enabled";
}
- private static final class InternationalCallOnWifiCallback
- implements InternationalCallOnWifiDialogFragment.Callback {
- private static final String TAG = InternationalCallOnWifiCallback.class.getCanonicalName();
-
- @Override
- public void continueCall(@NonNull String callId) {
- LogUtil.i(TAG, "Continuing call with ID: %s", callId);
- }
-
- @Override
- public void cancelCall(@NonNull String callId) {
- DialerCall call = CallList.getInstance().getCallById(callId);
- if (call == null) {
- LogUtil.i(TAG, "Call destroyed before the dialog is closed");
- return;
- }
-
- LogUtil.i(TAG, "Disconnecting international call on WiFi");
- call.disconnect();
- }
- }
-
private static final class SelectPhoneAccountListener
extends SelectPhoneAccountDialogFragment.SelectPhoneAccountListener {
private static final String TAG = SelectPhoneAccountListener.class.getCanonicalName();
diff --git a/java/com/android/incallui/InCallPresenter.java b/java/com/android/incallui/InCallPresenter.java
index 5e08c6969..526cc64d3 100644
--- a/java/com/android/incallui/InCallPresenter.java
+++ b/java/com/android/incallui/InCallPresenter.java
@@ -71,6 +71,8 @@ import com.android.incallui.latencyreport.LatencyReport;
import com.android.incallui.legacyblocking.BlockedNumberContentObserver;
import com.android.incallui.spam.SpamCallListListener;
import com.android.incallui.speakeasy.SpeakEasyCallManager;
+import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogActivity;
+import com.android.incallui.telecomeventui.InternationalCallOnWifiDialogFragment;
import com.android.incallui.videosurface.bindings.VideoSurfaceBindings;
import com.android.incallui.videosurface.protocol.VideoSurfaceTexture;
import com.android.incallui.videotech.utils.VideoUtils;
@@ -197,6 +199,7 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud
private InCallCameraManager inCallCameraManager;
private FilteredNumberAsyncQueryHandler filteredQueryHandler;
private CallList.Listener spamCallListListener;
+ private CallList.Listener activeCallsListener;
/** Whether or not we are currently bound and waiting for Telecom to send us a new call. */
private boolean boundAndWaitingForOutgoingCall;
/** Determines if the InCall UI is in fullscreen mode or not. */
@@ -383,6 +386,8 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud
new SpamCallListListener(
context, DialerExecutorComponent.get(context).dialerExecutorFactory());
this.callList.addListener(spamCallListListener);
+ activeCallsListener = new ActiveCallsCallListListener(context);
+ this.callList.addListener(activeCallsListener);
VideoPauseController.getInstance().setUp(this);
@@ -772,8 +777,22 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud
@Override
public void onInternationalCallOnWifi(@NonNull DialerCall call) {
LogUtil.enterBlock("InCallPresenter.onInternationalCallOnWifi");
+
+ if (!InternationalCallOnWifiDialogFragment.shouldShow(context)) {
+ LogUtil.i(
+ "InCallPresenter.onInternationalCallOnWifi",
+ "InternationalCallOnWifiDialogFragment.shouldShow returned false");
+ return;
+ }
+
if (inCallActivity != null) {
inCallActivity.showDialogForInternationalCallOnWifi(call);
+ } else {
+ Intent intent = new Intent(context, InternationalCallOnWifiDialogActivity.class);
+ // Prevent showing MainActivity with InternationalCallOnWifiDialogActivity on above
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ intent.putExtra(InternationalCallOnWifiDialogActivity.EXTRA_CALL_ID, call.getId());
+ context.startActivity(intent);
}
}
@@ -858,6 +877,7 @@ public class InCallPresenter implements CallList.Listener, AudioModeProvider.Aud
callList.getActiveOrBackgroundCall() != null || callList.getOutgoingCall() != null;
inCallActivity.dismissKeyguard(hasCall);
}
+
Trace.endSection();
}
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index c153503ac..9dfe7abcb 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -157,7 +157,7 @@ public class DialerCall implements VideoTechListener, StateChangedListener, Capa
private String lastForwardedNumber;
private boolean isCallForwarded;
private String callSubject;
- private PhoneAccountHandle phoneAccountHandle;
+ @Nullable private PhoneAccountHandle phoneAccountHandle;
@CallHistoryStatus private int callHistoryStatus = CALL_HISTORY_STATUS_UNKNOWN;
private boolean isSpam;
private boolean isBlocked;
diff --git a/java/com/android/incallui/res/layout/caller_in_conference.xml b/java/com/android/incallui/res/layout/caller_in_conference.xml
index be4eca5f6..23bb28512 100644
--- a/java/com/android/incallui/res/layout/caller_in_conference.xml
+++ b/java/com/android/incallui/res/layout/caller_in_conference.xml
@@ -68,7 +68,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/SecondaryText"
- android:textColor="@color/dialer_secondary_text_color_hiden"
+ android:textColor="@color/dialer_disabled_text_color"
android:visibility="gone"/>
<!-- Number -->
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index 2d70b6b12..7bfa100ea 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -49,6 +49,8 @@ import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.UiUtil;
import com.android.dialer.lettertile.LetterTileDrawable;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
import com.android.dialer.rtt.RttTranscript;
import com.android.dialer.rtt.RttTranscriptMessage;
import com.android.dialer.util.DrawableConverter;
@@ -219,6 +221,7 @@ public class RttChatFragment extends Fragment
submitButton = view.findViewById(R.id.rtt_chat_submit_button);
submitButton.setOnClickListener(
v -> {
+ Logger.get(getContext()).logImpression(DialerImpression.Type.RTT_SEND_BUTTON_CLICKED);
adapter.submitLocalMessage();
resumeInput("");
rttCallScreenDelegate.onLocalMessage(Constants.BUBBLE_BREAKER);
@@ -254,6 +257,8 @@ public class RttChatFragment extends Fragment
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
if (!TextUtils.isEmpty(editText.getText())) {
+ Logger.get(getContext())
+ .logImpression(DialerImpression.Type.RTT_KEYBOARD_SEND_BUTTON_CLICKED);
submitButton.performClick();
}
return true;
diff --git a/java/com/android/incallui/telecomeventui/AndroidManifest.xml b/java/com/android/incallui/telecomeventui/AndroidManifest.xml
index 861b9368a..a2134a3bd 100644
--- a/java/com/android/incallui/telecomeventui/AndroidManifest.xml
+++ b/java/com/android/incallui/telecomeventui/AndroidManifest.xml
@@ -12,4 +12,15 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest package="com.android.incallui.telecomeventui"/> \ No newline at end of file
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.incallui.telecomeventui">
+ <application>
+ <activity
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:name="com.android.incallui.telecomeventui.InternationalCallOnWifiDialogActivity"
+ android:noHistory="true"
+ android:theme="@style/Theme.Incall.DialogHolder"/>
+ </application>
+</manifest>
diff --git a/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java
new file mode 100644
index 000000000..192c1603a
--- /dev/null
+++ b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogActivity.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 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.incallui.telecomeventui;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import com.android.incallui.call.CallList;
+import com.android.incallui.call.DialerCall;
+
+/**
+ * Activity containing dialog that may be shown when users place an outgoing call to an
+ * international number while on Wifi.
+ */
+public class InternationalCallOnWifiDialogActivity extends AppCompatActivity
+ implements CallList.Listener {
+
+ public static final String EXTRA_CALL_ID = "extra_call_id";
+ private static final String TAG_INTERNATIONAL_CALL_ON_WIFI = "tag_international_call_on_wifi";
+
+ private String callId;
+
+ @Override
+ protected void onCreate(@Nullable Bundle bundle) {
+ super.onCreate(bundle);
+
+ callId = getIntent().getStringExtra(EXTRA_CALL_ID);
+ if (TextUtils.isEmpty(callId)) {
+ finish();
+ return;
+ }
+
+ InternationalCallOnWifiDialogFragment fragment =
+ InternationalCallOnWifiDialogFragment.newInstance(callId);
+ fragment.show(getSupportFragmentManager(), TAG_INTERNATIONAL_CALL_ON_WIFI);
+
+ CallList.getInstance().addListener(this);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ CallList.getInstance().removeListener(this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // We don't expect the activity to resume, except for orientation change.
+ if (!isChangingConfigurations()) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onDisconnect(DialerCall call) {
+ if (callId.equals(call.getId())) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onIncomingCall(DialerCall call) {}
+
+ @Override
+ public void onUpgradeToVideo(DialerCall call) {}
+
+ @Override
+ public void onUpgradeToRtt(DialerCall call, int rttRequestId) {}
+
+ @Override
+ public void onSessionModificationStateChange(DialerCall call) {}
+
+ @Override
+ public void onCallListChange(CallList callList) {}
+
+ @Override
+ public void onWiFiToLteHandover(DialerCall call) {}
+
+ @Override
+ public void onHandoverToWifiFailed(DialerCall call) {}
+
+ @Override
+ public void onInternationalCallOnWifi(@NonNull DialerCall call) {}
+}
diff --git a/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java
index 2b602f876..71a8be483 100644
--- a/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java
+++ b/java/com/android/incallui/telecomeventui/InternationalCallOnWifiDialogFragment.java
@@ -21,16 +21,18 @@ import android.app.Dialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v4.app.DialogFragment;
import android.support.v4.os.UserManagerCompat;
import android.view.View;
import android.widget.CheckBox;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.storage.StorageComponent;
+import com.android.incallui.call.CallList;
+import com.android.incallui.call.DialerCall;
/**
* Dialog that may be shown when users place an outgoing call to an international number while on
@@ -53,7 +55,7 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment {
return false;
}
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences preferences = StorageComponent.get(context).unencryptedSharedPrefs();
boolean shouldShow = preferences.getBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, true);
LogUtil.i("InternationalCallOnWifiDialogFragment.shouldShow", "result: %b", shouldShow);
@@ -61,27 +63,13 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment {
}
/**
- * Called in response to user interaction with the {@link InternationalCallOnWifiDialogFragment}.
- */
- public interface Callback {
-
- /** Indicates that the user wishes to proceed with the call represented by the given call id. */
- void continueCall(@NonNull String callId);
-
- /** Indicates that the user wishes to cancel the call represented by the given call id. */
- void cancelCall(@NonNull String callId);
- }
-
- /**
* Returns a new instance of {@link InternationalCallOnWifiDialogFragment} with the given
* callback.
*
* <p>Prefer this method over the default constructor.
*/
- public static InternationalCallOnWifiDialogFragment newInstance(
- @NonNull String callId, @NonNull Callback callback) {
+ public static InternationalCallOnWifiDialogFragment newInstance(@NonNull String callId) {
InternationalCallOnWifiDialogFragment fragment = new InternationalCallOnWifiDialogFragment();
- fragment.setCallback(callback);
Bundle args = new Bundle();
args.putString(ARG_CALL_ID, Assert.isNotNull(callId));
fragment.setArguments(args);
@@ -93,31 +81,12 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment {
* InternationalCallOnWifiDialogFragment InternationalCallOnWifiDialogFragments}.
*/
@VisibleForTesting
- static final String ALWAYS_SHOW_WARNING_PREFERENCE_KEY =
+ public static final String ALWAYS_SHOW_WARNING_PREFERENCE_KEY =
"ALWAYS_SHOW_INTERNATIONAL_CALL_ON_WIFI_WARNING";
/** Key in the arguments bundle for call id. */
private static final String ARG_CALL_ID = "call_id";
- /**
- * Callback which will receive information about user interactions with this dialog.
- *
- * <p>This is Nullable in the event that the dialog is destroyed by the framework, but doesn't
- * have a callback reattached. Ideally, the InCallActivity would implement the callback and we
- * would use FragmentUtils.getParentUnsafe instead of holding onto the callback here, but that's
- * not possible with the existing InCallActivity/InCallActivityCommon implementation.
- */
- @Nullable private Callback callback;
-
- /**
- * Sets the callback for this dialog.
- *
- * <p>Used to reset the callback after state changes.
- */
- public void setCallback(@NonNull Callback callback) {
- this.callback = Assert.isNotNull(callback);
- }
-
@NonNull
@Override
public Dialog onCreateDialog(Bundle bundle) {
@@ -134,7 +103,7 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment {
CheckBox alwaysWarn = dialogView.findViewById(R.id.always_warn);
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ SharedPreferences preferences = StorageComponent.get(getActivity()).unencryptedSharedPrefs();
// The default is set to false in this case to ensure that the first time the dialog opens,
// the checkbox is unchecked.
alwaysWarn.setChecked(preferences.getBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, false));
@@ -163,7 +132,7 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment {
preferences.edit().putBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, alwaysWarn).apply();
// Neither callback nor callId are null in normal circumstances. See comments on callback
- callback.continueCall(getArguments().getString(ARG_CALL_ID));
+ continueCall(getArguments().getString(ARG_CALL_ID));
}
private void onNegativeButtonClick(@NonNull SharedPreferences preferences, boolean alwaysWarn) {
@@ -174,6 +143,37 @@ public class InternationalCallOnWifiDialogFragment extends DialogFragment {
preferences.edit().putBoolean(ALWAYS_SHOW_WARNING_PREFERENCE_KEY, alwaysWarn).apply();
// Neither callback nor callId are null in normal circumstances. See comments on callback
- callback.cancelCall(getArguments().getString(ARG_CALL_ID));
+ cancelCall(getArguments().getString(ARG_CALL_ID));
+ }
+
+ private void continueCall(@NonNull String callId) {
+ LogUtil.i(
+ "InternationalCallOnWifiDialogFragment.continueCall",
+ "Continuing call with ID: %s",
+ callId);
+ InternationalCallOnWifiDialogActivity activity =
+ FragmentUtils.getParent(this, InternationalCallOnWifiDialogActivity.class);
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+
+ private void cancelCall(@NonNull String callId) {
+ DialerCall call = CallList.getInstance().getCallById(callId);
+ if (call == null) {
+ LogUtil.i(
+ "InternationalCallOnWifiDialogFragment.cancelCall",
+ "Call destroyed before the dialog is closed");
+ } else {
+ LogUtil.i(
+ "InternationalCallOnWifiDialogFragment.cancelCall",
+ "Disconnecting international call on WiFi");
+ call.disconnect();
+ }
+ InternationalCallOnWifiDialogActivity activity =
+ FragmentUtils.getParent(this, InternationalCallOnWifiDialogActivity.class);
+ if (activity != null) {
+ activity.finish();
+ }
}
}