ContactPreference.java revision 9e2eea1a8a4d34f8530fc9b042601d4a378bbf43
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.emergency.preferences;
17
18import android.app.AlertDialog;
19import android.content.Context;
20import android.content.DialogInterface;
21import android.content.Intent;
22import android.graphics.drawable.Drawable;
23import android.net.Uri;
24import android.os.Bundle;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.preference.Preference;
28import android.support.annotation.NonNull;
29import android.support.annotation.Nullable;
30import android.view.View;
31
32import com.android.emergency.EmergencyContactManager;
33import com.android.emergency.R;
34import com.android.internal.annotations.VisibleForTesting;
35import com.android.internal.logging.MetricsLogger;
36import com.android.internal.logging.MetricsProto.MetricsEvent;
37import com.android.settingslib.drawable.CircleFramedDrawable;
38
39
40/**
41 * A {@link Preference} to display or call a contact using the specified URI string.
42 */
43public class ContactPreference extends Preference {
44
45    private EmergencyContactManager.Contact mContact;
46    @Nullable private RemoveContactPreferenceListener mRemoveContactPreferenceListener;
47    @Nullable private AlertDialog mRemoveContactDialog;
48
49    /**
50     * Listener for removing a contact.
51     */
52    public interface RemoveContactPreferenceListener {
53        /**
54         * Callback to remove a contact preference.
55         */
56        void onRemoveContactPreference(ContactPreference preference);
57    }
58
59    /**
60     * Instantiates a ContactPreference that displays an emergency contact, taking in a Context and
61     * the Uri.
62     */
63    public ContactPreference(Context context, @NonNull Uri contactUri) {
64        super(context);
65        setOrder(DEFAULT_ORDER);
66
67        setUri(contactUri);
68
69        setWidgetLayoutResource(R.layout.preference_user_delete_widget);
70        setPersistent(false);
71    }
72
73    public void setUri(@NonNull Uri contactUri) {
74        if (mContact != null && !contactUri.equals(mContact.getContactUri()) &&
75                mRemoveContactDialog != null) {
76            mRemoveContactDialog.dismiss();
77        }
78
79        mContact = EmergencyContactManager.getContact(getContext(), contactUri);
80
81        setTitle(mContact.getName());
82        setKey(mContact.getContactUri().toString());
83        String summary = mContact.getPhoneType() == null ?
84                mContact.getPhoneNumber() :
85                String.format(
86                        getContext().getResources().getString(R.string.phone_type_and_phone_number),
87                        mContact.getPhoneType(),
88                        mContact.getPhoneNumber());
89        setSummary(summary);
90
91        // Update the message to show the correct name.
92        if (mRemoveContactDialog != null) {
93            mRemoveContactDialog.setMessage(
94                    String.format(getContext().getString(R.string.remove_contact),
95                            mContact.getName()));
96        }
97
98        //TODO: Consider doing the following in a non-UI thread.
99        Drawable icon;
100        if (mContact.getPhoto() != null) {
101            icon = new CircleFramedDrawable(mContact.getPhoto(),
102                    (int) getContext().getResources().getDimension(R.dimen.circle_avatar_size));
103        } else {
104            icon = getContext().getResources().getDrawable(R.drawable.ic_person_black_24dp);
105        }
106        setIcon(icon);
107    }
108
109    /** Listener to be informed when a contact preference should be deleted. */
110    public void setRemoveContactPreferenceListener(
111            RemoveContactPreferenceListener removeContactListener) {
112        mRemoveContactPreferenceListener = removeContactListener;
113        if (mRemoveContactPreferenceListener == null) {
114            mRemoveContactDialog = null;
115            return;
116        }
117        if (mRemoveContactDialog != null) {
118            return;
119        }
120        // Create the remove contact dialog
121        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
122        builder.setNegativeButton(getContext().getString(R.string.cancel), null);
123        builder.setPositiveButton(getContext().getString(R.string.remove),
124                new DialogInterface.OnClickListener() {
125                    @Override
126                    public void onClick(DialogInterface dialogInterface,
127                                        int which) {
128                        if (mRemoveContactPreferenceListener != null) {
129                            mRemoveContactPreferenceListener
130                                    .onRemoveContactPreference(ContactPreference.this);
131                        }
132                    }
133                });
134        builder.setMessage(String.format(getContext().getString(R.string.remove_contact),
135                mContact.getName()));
136        mRemoveContactDialog = builder.create();
137    }
138
139    @Override
140    protected void onBindView(View view) {
141        super.onBindView(view);
142        View deleteContactIcon = view.findViewById(R.id.delete_contact);
143        if (mRemoveContactPreferenceListener == null) {
144            deleteContactIcon.setVisibility(View.GONE);
145        } else {
146            deleteContactIcon.setOnClickListener(new View.OnClickListener() {
147                @Override
148                public void onClick(View view) {
149                    showRemoveContactDialog(null);
150                }
151            });
152
153        }
154    }
155
156    public Uri getContactUri() {
157        return mContact.getContactUri();
158    }
159
160    @VisibleForTesting
161    EmergencyContactManager.Contact getContact() {
162        return mContact;
163    }
164
165    @VisibleForTesting
166    AlertDialog getRemoveContactDialog() {
167        return mRemoveContactDialog;
168    }
169
170    /**
171     * Calls the contact.
172     */
173    public void callContact() {
174        Intent callIntent =
175                new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + mContact.getPhoneNumber()));
176        MetricsLogger.action(getContext(), MetricsEvent.ACTION_CALL_EMERGENCY_CONTACT);
177        getContext().startActivity(callIntent);
178    }
179
180    /**
181     * Displays a contact card for the contact.
182     */
183    public void displayContact() {
184        Intent contactIntent = new Intent(Intent.ACTION_VIEW);
185        contactIntent.setData(mContact.getContactLookupUri());
186        getContext().startActivity(contactIntent);
187    }
188
189    /** Shows the dialog to remove the contact, restoring it from {@code state} if it's not null. */
190    private void showRemoveContactDialog(Bundle state) {
191        if (mRemoveContactDialog == null) {
192            return;
193        }
194        if (state != null) {
195            mRemoveContactDialog.onRestoreInstanceState(state);
196        }
197        mRemoveContactDialog.show();
198    }
199
200    @Override
201    protected Parcelable onSaveInstanceState() {
202        final Parcelable superState = super.onSaveInstanceState();
203        if (mRemoveContactDialog == null || !mRemoveContactDialog.isShowing()) {
204            return superState;
205        }
206        final SavedState myState = new SavedState(superState);
207        myState.isDialogShowing = true;
208        myState.dialogBundle = mRemoveContactDialog.onSaveInstanceState();
209        return myState;
210    }
211
212    @Override
213    protected void onRestoreInstanceState(Parcelable state) {
214        if (state == null || !state.getClass().equals(SavedState.class)) {
215            // Didn't save state for us in onSaveInstanceState
216            super.onRestoreInstanceState(state);
217            return;
218        }
219        SavedState myState = (SavedState) state;
220        super.onRestoreInstanceState(myState.getSuperState());
221        if (myState.isDialogShowing) {
222            showRemoveContactDialog(myState.dialogBundle);
223        }
224    }
225
226    private static class SavedState extends BaseSavedState {
227        boolean isDialogShowing;
228        Bundle dialogBundle;
229
230        public SavedState(Parcel source) {
231            super(source);
232            isDialogShowing = source.readInt() == 1;
233            dialogBundle = source.readBundle();
234        }
235
236        @Override
237        public void writeToParcel(Parcel dest, int flags) {
238            super.writeToParcel(dest, flags);
239            dest.writeInt(isDialogShowing ? 1 : 0);
240            dest.writeBundle(dialogBundle);
241        }
242
243        public SavedState(Parcelable superState) {
244            super(superState);
245        }
246
247        public static final Parcelable.Creator<SavedState> CREATOR =
248                new Parcelable.Creator<SavedState>() {
249                    public SavedState createFromParcel(Parcel in) {
250                        return new SavedState(in);
251                    }
252
253                    public SavedState[] newArray(int size) {
254                        return new SavedState[size];
255                    }
256                };
257    }
258}