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