blob: 1454f6b5b454824be27e820cc4c68e3a8ab7b6b2 [file] [log] [blame]
Akshay Kannancdb6c142016-01-20 18:25:44 -08001/*
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 */
mariagpuyol58748352016-03-09 15:36:28 -080016package com.android.emergency.preferences;
Akshay Kannancdb6c142016-01-20 18:25:44 -080017
Akshay Kannan44ef39d2016-01-26 09:08:41 -080018import android.app.AlertDialog;
mariagpuyole0f631b2016-08-16 18:58:26 -070019import android.content.ComponentName;
Akshay Kannancdb6c142016-01-20 18:25:44 -080020import android.content.Context;
mariagpuyold19ace52016-02-12 10:37:26 -080021import android.content.DialogInterface;
Akshay Kannancdb6c142016-01-20 18:25:44 -080022import android.content.Intent;
mariagpuyole0f631b2016-08-16 18:58:26 -070023import android.content.pm.PackageManager;
24import android.content.pm.ResolveInfo;
mariagpuyol95dc0402016-02-17 11:12:46 -080025import android.graphics.drawable.Drawable;
Akshay Kannancdb6c142016-01-20 18:25:44 -080026import android.net.Uri;
mariagpuyol53745bf2016-03-23 14:43:55 -070027import android.os.Bundle;
28import android.os.Parcel;
29import android.os.Parcelable;
Akshay Kannancdb6c142016-01-20 18:25:44 -080030import android.preference.Preference;
mariagpuyolaee23782016-02-16 13:29:49 -080031import android.support.annotation.NonNull;
mariagpuyol16472ca2016-02-16 17:49:26 -080032import android.support.annotation.Nullable;
mariagpuyol9bc08182016-05-13 14:54:49 -070033import android.text.BidiFormatter;
34import android.text.TextDirectionHeuristics;
mariagpuyold19ace52016-02-12 10:37:26 -080035import android.view.View;
mariagpuyold19ace52016-02-12 10:37:26 -080036
mariagpuyolacef32a2016-12-12 11:33:20 -080037import com.android.emergency.CircleFramedDrawable;
mariagpuyol58748352016-03-09 15:36:28 -080038import com.android.emergency.EmergencyContactManager;
mariagpuyol58748352016-03-09 15:36:28 -080039import com.android.emergency.R;
mariagpuyol9e2eea12016-04-01 18:10:12 -070040import com.android.internal.annotations.VisibleForTesting;
Akshay Kannan44ef39d2016-01-26 09:08:41 -080041import com.android.internal.logging.MetricsLogger;
Tamas Berghammer2fdeb9a2016-06-22 15:28:50 +010042import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Akshay Kannan44ef39d2016-01-26 09:08:41 -080043
mariagpuyole0f631b2016-08-16 18:58:26 -070044import java.util.List;
45
Akshay Kannancdb6c142016-01-20 18:25:44 -080046
47/**
mariagpuyol5cf7f732016-03-08 09:48:15 -080048 * A {@link Preference} to display or call a contact using the specified URI string.
Akshay Kannancdb6c142016-01-20 18:25:44 -080049 */
50public class ContactPreference extends Preference {
51
mariagpuyol53745bf2016-03-23 14:43:55 -070052 private EmergencyContactManager.Contact mContact;
mariagpuyol609f68a2016-02-22 17:45:47 -080053 @Nullable private RemoveContactPreferenceListener mRemoveContactPreferenceListener;
mariagpuyol53745bf2016-03-23 14:43:55 -070054 @Nullable private AlertDialog mRemoveContactDialog;
mariagpuyold19ace52016-02-12 10:37:26 -080055
56 /**
mariagpuyol609f68a2016-02-22 17:45:47 -080057 * Listener for removing a contact.
mariagpuyold19ace52016-02-12 10:37:26 -080058 */
mariagpuyol609f68a2016-02-22 17:45:47 -080059 public interface RemoveContactPreferenceListener {
mariagpuyold19ace52016-02-12 10:37:26 -080060 /**
mariagpuyol609f68a2016-02-22 17:45:47 -080061 * Callback to remove a contact preference.
mariagpuyold19ace52016-02-12 10:37:26 -080062 */
mariagpuyol609f68a2016-02-22 17:45:47 -080063 void onRemoveContactPreference(ContactPreference preference);
mariagpuyold19ace52016-02-12 10:37:26 -080064 }
Akshay Kannancdb6c142016-01-20 18:25:44 -080065
66 /**
67 * Instantiates a ContactPreference that displays an emergency contact, taking in a Context and
mariagpuyol5cf7f732016-03-08 09:48:15 -080068 * the Uri.
Akshay Kannancdb6c142016-01-20 18:25:44 -080069 */
mariagpuyol5cf7f732016-03-08 09:48:15 -080070 public ContactPreference(Context context, @NonNull Uri contactUri) {
Akshay Kannancdb6c142016-01-20 18:25:44 -080071 super(context);
mariagpuyol609f68a2016-02-22 17:45:47 -080072 setOrder(DEFAULT_ORDER);
mariagpuyol53745bf2016-03-23 14:43:55 -070073
74 setUri(contactUri);
75
76 setWidgetLayoutResource(R.layout.preference_user_delete_widget);
77 setPersistent(false);
78 }
79
80 public void setUri(@NonNull Uri contactUri) {
81 if (mContact != null && !contactUri.equals(mContact.getContactUri()) &&
82 mRemoveContactDialog != null) {
83 mRemoveContactDialog.dismiss();
84 }
85
86 mContact = EmergencyContactManager.getContact(getContext(), contactUri);
87
mariagpuyol5cf7f732016-03-08 09:48:15 -080088 setTitle(mContact.getName());
mariagpuyol53745bf2016-03-23 14:43:55 -070089 setKey(mContact.getContactUri().toString());
mariagpuyolf9ab89a2016-03-10 09:19:07 -080090 String summary = mContact.getPhoneType() == null ?
91 mContact.getPhoneNumber() :
92 String.format(
mariagpuyol53745bf2016-03-23 14:43:55 -070093 getContext().getResources().getString(R.string.phone_type_and_phone_number),
mariagpuyolf9ab89a2016-03-10 09:19:07 -080094 mContact.getPhoneType(),
mariagpuyol9bc08182016-05-13 14:54:49 -070095 BidiFormatter.getInstance().unicodeWrap(mContact.getPhoneNumber(),
96 TextDirectionHeuristics.LTR));
mariagpuyolf9ab89a2016-03-10 09:19:07 -080097 setSummary(summary);
mariagpuyol53745bf2016-03-23 14:43:55 -070098
99 // Update the message to show the correct name.
100 if (mRemoveContactDialog != null) {
101 mRemoveContactDialog.setMessage(
102 String.format(getContext().getString(R.string.remove_contact),
103 mContact.getName()));
104 }
mariagpuyol95dc0402016-02-17 11:12:46 -0800105
106 //TODO: Consider doing the following in a non-UI thread.
mariagpuyol9be32652016-03-16 12:34:53 -0700107 Drawable icon;
108 if (mContact.getPhoto() != null) {
109 icon = new CircleFramedDrawable(mContact.getPhoto(),
mariagpuyol53745bf2016-03-23 14:43:55 -0700110 (int) getContext().getResources().getDimension(R.dimen.circle_avatar_size));
mariagpuyol9be32652016-03-16 12:34:53 -0700111 } else {
mariagpuyol53745bf2016-03-23 14:43:55 -0700112 icon = getContext().getResources().getDrawable(R.drawable.ic_person_black_24dp);
mariagpuyol9be32652016-03-16 12:34:53 -0700113 }
mariagpuyol95dc0402016-02-17 11:12:46 -0800114 setIcon(icon);
115 }
116
mariagpuyol609f68a2016-02-22 17:45:47 -0800117 /** Listener to be informed when a contact preference should be deleted. */
118 public void setRemoveContactPreferenceListener(
119 RemoveContactPreferenceListener removeContactListener) {
120 mRemoveContactPreferenceListener = removeContactListener;
mariagpuyol53745bf2016-03-23 14:43:55 -0700121 if (mRemoveContactPreferenceListener == null) {
122 mRemoveContactDialog = null;
123 return;
124 }
125 if (mRemoveContactDialog != null) {
126 return;
127 }
128 // Create the remove contact dialog
129 AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
130 builder.setNegativeButton(getContext().getString(R.string.cancel), null);
131 builder.setPositiveButton(getContext().getString(R.string.remove),
132 new DialogInterface.OnClickListener() {
133 @Override
134 public void onClick(DialogInterface dialogInterface,
135 int which) {
136 if (mRemoveContactPreferenceListener != null) {
137 mRemoveContactPreferenceListener
138 .onRemoveContactPreference(ContactPreference.this);
139 }
140 }
141 });
142 builder.setMessage(String.format(getContext().getString(R.string.remove_contact),
143 mContact.getName()));
144 mRemoveContactDialog = builder.create();
mariagpuyol609f68a2016-02-22 17:45:47 -0800145 }
146
mariagpuyold19ace52016-02-12 10:37:26 -0800147 @Override
148 protected void onBindView(View view) {
149 super.onBindView(view);
150 View deleteContactIcon = view.findViewById(R.id.delete_contact);
mariagpuyol609f68a2016-02-22 17:45:47 -0800151 if (mRemoveContactPreferenceListener == null) {
mariagpuyol16472ca2016-02-16 17:49:26 -0800152 deleteContactIcon.setVisibility(View.GONE);
153 } else {
mariagpuyol609f68a2016-02-22 17:45:47 -0800154 deleteContactIcon.setOnClickListener(new View.OnClickListener() {
155 @Override
156 public void onClick(View view) {
mariagpuyol53745bf2016-03-23 14:43:55 -0700157 showRemoveContactDialog(null);
mariagpuyol609f68a2016-02-22 17:45:47 -0800158 }
159 });
160
mariagpuyold19ace52016-02-12 10:37:26 -0800161 }
Akshay Kannancdb6c142016-01-20 18:25:44 -0800162 }
163
mariagpuyol609f68a2016-02-22 17:45:47 -0800164 public Uri getContactUri() {
mariagpuyol5cf7f732016-03-08 09:48:15 -0800165 return mContact.getContactUri();
mariagpuyol609f68a2016-02-22 17:45:47 -0800166 }
167
mariagpuyol9e2eea12016-04-01 18:10:12 -0700168 @VisibleForTesting
169 EmergencyContactManager.Contact getContact() {
170 return mContact;
171 }
172
173 @VisibleForTesting
174 AlertDialog getRemoveContactDialog() {
175 return mRemoveContactDialog;
176 }
177
Akshay Kannancdb6c142016-01-20 18:25:44 -0800178 /**
Akshay Kannan44ef39d2016-01-26 09:08:41 -0800179 * Calls the contact.
180 */
mariagpuyol5cf7f732016-03-08 09:48:15 -0800181 public void callContact() {
182 Intent callIntent =
183 new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + mContact.getPhoneNumber()));
mariagpuyole0f631b2016-08-16 18:58:26 -0700184 PackageManager packageManager = getContext().getPackageManager();
185 List<ResolveInfo> infos =
186 packageManager.queryIntentActivities(callIntent, PackageManager.MATCH_SYSTEM_ONLY);
187 if (infos == null || infos.isEmpty()) {
188 return;
189 }
190 callIntent.setComponent(new ComponentName(infos.get(0).activityInfo.packageName,
191 infos.get(0).activityInfo.name));
192
mariagpuyol5cf7f732016-03-08 09:48:15 -0800193 MetricsLogger.action(getContext(), MetricsEvent.ACTION_CALL_EMERGENCY_CONTACT);
194 getContext().startActivity(callIntent);
mariagpuyol0504a442016-02-17 16:22:57 -0800195 }
mariagpuyol36b3f9d2016-03-11 16:02:31 -0800196
197 /**
198 * Displays a contact card for the contact.
199 */
200 public void displayContact() {
201 Intent contactIntent = new Intent(Intent.ACTION_VIEW);
202 contactIntent.setData(mContact.getContactLookupUri());
203 getContext().startActivity(contactIntent);
204 }
mariagpuyol53745bf2016-03-23 14:43:55 -0700205
206 /** Shows the dialog to remove the contact, restoring it from {@code state} if it's not null. */
207 private void showRemoveContactDialog(Bundle state) {
208 if (mRemoveContactDialog == null) {
209 return;
210 }
211 if (state != null) {
212 mRemoveContactDialog.onRestoreInstanceState(state);
213 }
214 mRemoveContactDialog.show();
215 }
216
217 @Override
218 protected Parcelable onSaveInstanceState() {
219 final Parcelable superState = super.onSaveInstanceState();
220 if (mRemoveContactDialog == null || !mRemoveContactDialog.isShowing()) {
221 return superState;
222 }
223 final SavedState myState = new SavedState(superState);
224 myState.isDialogShowing = true;
225 myState.dialogBundle = mRemoveContactDialog.onSaveInstanceState();
226 return myState;
227 }
228
229 @Override
230 protected void onRestoreInstanceState(Parcelable state) {
231 if (state == null || !state.getClass().equals(SavedState.class)) {
232 // Didn't save state for us in onSaveInstanceState
233 super.onRestoreInstanceState(state);
234 return;
235 }
236 SavedState myState = (SavedState) state;
237 super.onRestoreInstanceState(myState.getSuperState());
238 if (myState.isDialogShowing) {
239 showRemoveContactDialog(myState.dialogBundle);
240 }
241 }
242
243 private static class SavedState extends BaseSavedState {
244 boolean isDialogShowing;
245 Bundle dialogBundle;
246
247 public SavedState(Parcel source) {
248 super(source);
249 isDialogShowing = source.readInt() == 1;
250 dialogBundle = source.readBundle();
251 }
252
253 @Override
254 public void writeToParcel(Parcel dest, int flags) {
255 super.writeToParcel(dest, flags);
256 dest.writeInt(isDialogShowing ? 1 : 0);
257 dest.writeBundle(dialogBundle);
258 }
259
260 public SavedState(Parcelable superState) {
261 super(superState);
262 }
263
264 public static final Parcelable.Creator<SavedState> CREATOR =
265 new Parcelable.Creator<SavedState>() {
266 public SavedState createFromParcel(Parcel in) {
267 return new SavedState(in);
268 }
269
270 public SavedState[] newArray(int size) {
271 return new SavedState[size];
272 }
273 };
274 }
mariagpuyole0f631b2016-08-16 18:58:26 -0700275}