/* * Copyright (C) 2014 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.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.SubscriptionInfo; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.TextView; import com.android.contacts.common.compat.PhoneAccountCompat; import com.android.dialer.contacts.resources.R; 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; /** * Dialog that allows the user to select a phone accounts for a given action. Optionally provides * the choice to set the phone account as default. */ public class SelectPhoneAccountDialogFragment extends DialogFragment { @VisibleForTesting public static final String ARG_OPTIONS = "options"; private static final String ARG_IS_DEFAULT_CHECKED = "is_default_checked"; private SelectPhoneAccountDialogOptions options = SelectPhoneAccountDialogOptions.getDefaultInstance(); private SelectPhoneAccountListener listener; private boolean isDefaultChecked; private boolean isSelected; /** Create new fragment instance. */ public static SelectPhoneAccountDialogFragment newInstance( SelectPhoneAccountDialogOptions options, SelectPhoneAccountListener listener) { SelectPhoneAccountDialogFragment fragment = new SelectPhoneAccountDialogFragment(); fragment.setListener(listener); Bundle arguments = new Bundle(); ProtoParsers.put(arguments, ARG_OPTIONS, options); fragment.setArguments(arguments); return fragment; } public void setListener(SelectPhoneAccountListener listener) { this.listener = listener; } @Nullable @VisibleForTesting public SelectPhoneAccountListener getListener() { return listener; } @VisibleForTesting public boolean canSetDefault() { return options.getCanSetDefault(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(ARG_IS_DEFAULT_CHECKED, isDefaultChecked); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { options = ProtoParsers.getTrusted( getArguments(), ARG_OPTIONS, SelectPhoneAccountDialogOptions.getDefaultInstance()); if (savedInstanceState != null) { isDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED); } isSelected = false; final DialogInterface.OnClickListener selectionListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int 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, isDefaultChecked); result.putString(SelectPhoneAccountListener.EXTRA_CALL_ID, getCallId()); if (listener != null) { listener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result); } } }; final CompoundButton.OnCheckedChangeListener checkListener = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton check, boolean isChecked) { isDefaultChecked = isChecked; } }; AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); ListAdapter selectAccountListAdapter = new SelectAccountListAdapter( builder.getContext(), R.layout.select_account_list_item, options); AlertDialog dialog = builder .setTitle( options.hasTitle() ? options.getTitle() : R.string.select_account_dialog_title) .setAdapter(selectAccountListAdapter, selectionListener) .create(); if (options.getCanSetDefault()) { // Generate custom checkbox view, lint suppressed since no appropriate parent (is dialog) @SuppressLint("InflateParams") LinearLayout checkboxLayout = (LinearLayout) LayoutInflater.from(builder.getContext()) .inflate(R.layout.default_account_checkbox, null); CheckBox checkBox = checkboxLayout.findViewById(R.id.default_account_checkbox_view); checkBox.setOnCheckedChangeListener(checkListener); checkBox.setChecked(isDefaultChecked); TextView textView = checkboxLayout.findViewById(R.id.default_account_checkbox_text); int setDefaultResId = options.hasSetDefaultLabel() ? options.getSetDefaultLabel() : R.string.set_default_account; textView.setText(setDefaultResId); textView.setOnClickListener((view) -> checkBox.performClick()); checkboxLayout.setOnClickListener((view) -> checkBox.performClick()); checkboxLayout.setContentDescription(getString(setDefaultResId)); dialog.getListView().addFooterView(checkboxLayout); } return dialog; } @Override public void onCancel(DialogInterface dialog) { if (!isSelected && listener != null) { Bundle result = new Bundle(); result.putString(SelectPhoneAccountListener.EXTRA_CALL_ID, getCallId()); listener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, result); } super.onCancel(dialog); } @Nullable private String getCallId() { return options.getCallId(); } public static class SelectPhoneAccountListener extends ResultReceiver { static final int RESULT_SELECTED = 1; static final int RESULT_DISMISSED = 2; static final String EXTRA_SELECTED_ACCOUNT_HANDLE = "extra_selected_account_handle"; static final String EXTRA_SET_DEFAULT = "extra_set_default"; static final String EXTRA_CALL_ID = "extra_call_id"; protected SelectPhoneAccountListener() { super(new Handler()); } @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == RESULT_SELECTED) { onPhoneAccountSelected( resultData.getParcelable(EXTRA_SELECTED_ACCOUNT_HANDLE), resultData.getBoolean(EXTRA_SET_DEFAULT), resultData.getString(EXTRA_CALL_ID)); } else if (resultCode == RESULT_DISMISSED) { onDialogDismissed(resultData.getString(EXTRA_CALL_ID)); } } public void onPhoneAccountSelected( PhoneAccountHandle selectedAccountHandle, boolean setDefault, @Nullable String callId) {} public void onDialogDismissed(@Nullable String callId) {} } static class SelectAccountListAdapter extends ArrayAdapter { private int mResId; private final SelectPhoneAccountDialogOptions options; SelectAccountListAdapter( 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); View rowView; final ViewHolder holder; if (convertView == null) { // Cache views for faster scrolling rowView = inflater.inflate(mResId, null); holder = new ViewHolder(); holder.labelTextView = (TextView) rowView.findViewById(R.id.label); holder.numberTextView = (TextView) rowView.findViewById(R.id.number); holder.hintTextView = rowView.findViewById(R.id.hint); holder.imageView = (ImageView) rowView.findViewById(R.id.icon); rowView.setTag(holder); } else { rowView = convertView; holder = (ViewHolder) rowView.getTag(); } SelectPhoneAccountDialogOptions.Entry entry = getItem(position); PhoneAccountHandle accountHandle = SelectPhoneAccountDialogOptionsUtil.getPhoneAccountHandle(entry); PhoneAccount account = getContext().getSystemService(TelecomManager.class).getPhoneAccount(accountHandle); if (account == null) { return rowView; } holder.labelTextView.setText(account.getLabel()); if (account.getAddress() == null || TextUtils.isEmpty(account.getAddress().getSchemeSpecificPart())) { holder.numberTextView.setVisibility(View.GONE); } else { holder.numberTextView.setVisibility(View.VISIBLE); holder.numberTextView.setText( PhoneNumberHelper.formatNumberForDisplay( getContext(), account.getAddress().getSchemeSpecificPart(), getCountryIso(getContext(), accountHandle))); } holder.imageView.setImageDrawable( PhoneAccountCompat.createIconDrawable(account, getContext())); 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; } private static String getCountryIso( Context context, @NonNull PhoneAccountHandle phoneAccountHandle) { Optional info = TelecomUtil.getSubscriptionInfo(context, phoneAccountHandle); if (!info.isPresent()) { return GeoUtil.getCurrentCountryIso(context); } return info.get().getCountryIso().toUpperCase(); } static final class ViewHolder { TextView labelTextView; TextView numberTextView; TextView hintTextView; ImageView imageView; } } }