• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 
17 package com.android.contacts.activities;
18 
19 import com.android.contacts.ContactSaveService;
20 import com.android.contacts.ContactsActivity;
21 import com.android.contacts.R;
22 import com.android.contacts.common.model.AccountTypeManager;
23 import com.android.contacts.common.model.account.AccountType;
24 import com.android.contacts.common.model.account.AccountWithDataSet;
25 import com.android.contacts.common.util.ImplicitIntentsUtil;
26 import com.android.contacts.editor.ContactEditorBaseFragment;
27 import com.android.contacts.editor.ContactEditorFragment;
28 import com.android.contacts.editor.EditorIntents;
29 import com.android.contacts.interactions.ContactDeletionInteraction;
30 import com.android.contacts.util.DialogManager;
31 
32 import android.app.ActionBar;
33 import android.app.Dialog;
34 import android.content.ContentValues;
35 import android.content.Intent;
36 import android.net.Uri;
37 import android.os.Bundle;
38 import android.provider.ContactsContract.Contacts;
39 import android.provider.ContactsContract.RawContacts;
40 import android.util.Log;
41 import android.view.View;
42 import android.view.inputmethod.InputMethodManager;
43 
44 import java.util.ArrayList;
45 
46 /**
47  * Base Activity for contact editors.
48  */
49 abstract public class ContactEditorBaseActivity extends ContactsActivity
50         implements DialogManager.DialogShowingViewActivity {
51     protected static final String TAG = "ContactEditorActivity";
52 
53     /**
54      * Intent action to edit a contact with all available field inputs displayed.
55      *
56      * Only used to open the "fully expanded" editor -- {@link ContactEditorActivity}.
57      */
58     public static final String ACTION_EDIT = "com.android.contacts.action.FULL_EDIT";
59 
60     /**
61      * Intent action to insert a new contact with all available field inputs displayed.
62      *
63      * Only used to open the "fully expanded" editor -- {@link ContactEditorActivity}.
64      */
65     public static final String ACTION_INSERT = "com.android.contacts.action.FULL_INSERT";
66 
67     public static final String ACTION_JOIN_COMPLETED = "joinCompleted";
68     public static final String ACTION_SAVE_COMPLETED = "saveCompleted";
69 
70     /**
71      * Contract for contact editors Fragments that are managed by this Activity.
72      */
73     public interface ContactEditor {
74 
75         /**
76          * Modes that specify what the AsyncTask has to perform after saving
77          */
78         public interface SaveMode {
79             /**
80              * Close the editor after saving
81              */
82             public static final int CLOSE = 0;
83 
84             /**
85              * Reload the data so that the user can continue editing
86              */
87             public static final int RELOAD = 1;
88 
89             /**
90              * Split the contact after saving
91              */
92             public static final int SPLIT = 2;
93 
94             /**
95              * Join another contact after saving
96              */
97             public static final int JOIN = 3;
98 
99             /**
100              * Navigate to the compact editor view after saving.
101              */
102             public static final int COMPACT = 4;
103         }
104 
105         /**
106          * The status of the contact editor.
107          */
108         public interface Status {
109             /**
110              * The loader is fetching data
111              */
112             public static final int LOADING = 0;
113 
114             /**
115              * Not currently busy. We are waiting for the user to enter data
116              */
117             public static final int EDITING = 1;
118 
119             /**
120              * The data is currently being saved. This is used to prevent more
121              * auto-saves (they shouldn't overlap)
122              */
123             public static final int SAVING = 2;
124 
125             /**
126              * Prevents any more saves. This is used if in the following cases:
127              * - After Save/Close
128              * - After Revert
129              * - After the user has accepted an edit suggestion
130              * - After the user chooses to expand the compact editor
131              */
132             public static final int CLOSING = 3;
133 
134             /**
135              * Prevents saving while running a child activity.
136              */
137             public static final int SUB_ACTIVITY = 4;
138         }
139 
140         /**
141          * Sets the hosting Activity that will receive callbacks from the contact editor.
142          */
setListener(ContactEditorBaseFragment.Listener listener)143         void setListener(ContactEditorBaseFragment.Listener listener);
144 
145         /**
146          * Initialize the contact editor.
147          */
load(String action, Uri lookupUri, Bundle intentExtras)148         void load(String action, Uri lookupUri, Bundle intentExtras);
149 
150         /**
151          * Applies extras from the hosting Activity to the first writable raw contact.
152          */
setIntentExtras(Bundle extras)153         void setIntentExtras(Bundle extras);
154 
155         /**
156          * Saves or creates the contact based on the mode, and if successful
157          * finishes the activity.
158          *
159          * @param backPressed whether the save was initiated as a result of a back button press
160          *         or because the framework stopped the editor Activity
161          */
save(int saveMode, boolean backPressed)162         boolean save(int saveMode, boolean backPressed);
163 
164         /**
165          * If there are no unsaved changes, just close the editor, otherwise the user is prompted
166          * before discarding unsaved changes.
167          */
revert()168         boolean revert();
169 
170         /**
171          * Invoked after the contact is saved.
172          */
onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded, Uri contactLookupUri, Bundle updatedPhotos, boolean backPressed, long photoId, long nameId)173         void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
174                 Uri contactLookupUri, Bundle updatedPhotos, boolean backPressed, long photoId,
175                 long nameId);
176 
177         /**
178          * Invoked after the contact is joined.
179          */
onJoinCompleted(Uri uri)180         void onJoinCompleted(Uri uri);
181     }
182 
183     /**
184      * Boolean intent key that specifies that this activity should finish itself
185      * (instead of launching a new view intent) after the editor changes have been
186      * saved.
187      */
188     public static final String INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED =
189             "finishActivityOnSaveCompleted";
190 
191     protected ContactEditor mFragment;
192     private boolean mFinishActivityOnSaveCompleted;
193 
194     private DialogManager mDialogManager = new DialogManager(this);
195 
196     @Override
onCreate(Bundle savedState)197     public void onCreate(Bundle savedState) {
198         super.onCreate(savedState);
199 
200         final Intent intent = getIntent();
201         final String action = intent.getAction();
202 
203         // Determine whether or not this activity should be finished after the user is done
204         // editing the contact or if this activity should launch another activity to view the
205         // contact's details.
206         mFinishActivityOnSaveCompleted = intent.getBooleanExtra(
207                 INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, false);
208 
209         // The only situation where action could be ACTION_JOIN_COMPLETED is if the
210         // user joined the contact with another and closed the activity before
211         // the save operation was completed.  The activity should remain closed then.
212         if (ACTION_JOIN_COMPLETED.equals(action)) {
213             finish();
214             return;
215         }
216 
217         if (ACTION_SAVE_COMPLETED.equals(action)) {
218             finish();
219             return;
220         }
221 
222         ActionBar actionBar = getActionBar();
223         if (actionBar != null) {
224             if (Intent.ACTION_EDIT.equals(action) || ACTION_EDIT.equals(action)) {
225                 actionBar.setTitle(getResources().getString(
226                         R.string.contact_editor_title_existing_contact));
227             } else {
228                 actionBar.setTitle(getResources().getString(
229                         R.string.contact_editor_title_new_contact));
230             }
231             actionBar.setDisplayShowHomeEnabled(true);
232             actionBar.setDisplayHomeAsUpEnabled(true);
233         }
234     }
235 
236     @Override
onPause()237     protected void onPause() {
238         super.onPause();
239         final InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
240         final View currentFocus = getCurrentFocus();
241         if (imm != null && currentFocus != null) {
242             imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
243         }
244     }
245 
246     @Override
onNewIntent(Intent intent)247     protected void onNewIntent(Intent intent) {
248         super.onNewIntent(intent);
249 
250         if (mFragment == null) {
251             return;
252         }
253 
254         String action = intent.getAction();
255         if (Intent.ACTION_EDIT.equals(action) || ACTION_EDIT.equals(action)) {
256             mFragment.setIntentExtras(intent.getExtras());
257         } else if (ACTION_SAVE_COMPLETED.equals(action)) {
258             mFragment.onSaveCompleted(true,
259                     intent.getIntExtra(ContactEditorFragment.SAVE_MODE_EXTRA_KEY,
260                             ContactEditor.SaveMode.CLOSE),
261                     intent.getBooleanExtra(ContactSaveService.EXTRA_SAVE_SUCCEEDED, false),
262                     intent.getData(),
263                     (Bundle) intent.getParcelableExtra(ContactSaveService.EXTRA_UPDATED_PHOTOS),
264                     intent.getBooleanExtra(ContactEditorFragment.INTENT_EXTRA_SAVE_BACK_PRESSED,
265                             false),
266                     intent.getLongExtra(ContactEditorFragment.INTENT_EXTRA_PHOTO_ID, -1),
267                     intent.getLongExtra(ContactEditorFragment.INTENT_EXTRA_NAME_ID, -1));
268         } else if (ACTION_JOIN_COMPLETED.equals(action)) {
269             mFragment.onJoinCompleted(intent.getData());
270         }
271     }
272 
273     @Override
onCreateDialog(int id, Bundle args)274     protected Dialog onCreateDialog(int id, Bundle args) {
275         if (DialogManager.isManagedId(id)) return mDialogManager.onCreateDialog(id, args);
276 
277         // Nobody knows about the Dialog
278         Log.w(TAG, "Unknown dialog requested, id: " + id + ", args: " + args);
279         return null;
280     }
281 
282     protected final ContactEditorBaseFragment.Listener  mFragmentListener =
283             new ContactEditorBaseFragment.Listener() {
284 
285         @Override
286         public void onDeleteRequested(Uri contactUri) {
287             ContactDeletionInteraction.start(ContactEditorBaseActivity.this, contactUri, true);
288         }
289 
290         @Override
291         public void onReverted() {
292             finish();
293         }
294 
295         @Override
296         public void onSaveFinished(Intent resultIntent) {
297             final boolean backPressed = resultIntent == null ? false : resultIntent.getBooleanExtra(
298                     ContactEditorBaseFragment.INTENT_EXTRA_SAVE_BACK_PRESSED, false);
299             if (mFinishActivityOnSaveCompleted) {
300                 setResult(resultIntent == null ? RESULT_CANCELED : RESULT_OK, resultIntent);
301             } else if (resultIntent != null) {
302                 if (backPressed) {
303                     ImplicitIntentsUtil.startActivityInApp(ContactEditorBaseActivity.this,
304                             resultIntent);
305                 }
306             }
307             finish();
308         }
309 
310         @Override
311         public void onContactSplit(Uri newLookupUri) {
312             finish();
313         }
314 
315         @Override
316         public void onContactNotFound() {
317             finish();
318         }
319 
320         @Override
321         public void onEditOtherContactRequested(
322                 Uri contactLookupUri, ArrayList<ContentValues> values) {
323             final Intent intent = EditorIntents.createEditOtherContactIntent(
324                     contactLookupUri, values);
325             ImplicitIntentsUtil.startActivityInApp(ContactEditorBaseActivity.this, intent);
326             finish();
327         }
328 
329         @Override
330         public void onCustomCreateContactActivityRequested(AccountWithDataSet account,
331                 Bundle intentExtras) {
332             final AccountTypeManager accountTypes =
333                     AccountTypeManager.getInstance(ContactEditorBaseActivity.this);
334             final AccountType accountType = accountTypes.getAccountType(
335                     account.type, account.dataSet);
336 
337             Intent intent = new Intent();
338             intent.setClassName(accountType.syncAdapterPackageName,
339                     accountType.getCreateContactActivityClassName());
340             intent.setAction(Intent.ACTION_INSERT);
341             intent.setType(Contacts.CONTENT_ITEM_TYPE);
342             if (intentExtras != null) {
343                 intent.putExtras(intentExtras);
344             }
345             intent.putExtra(RawContacts.ACCOUNT_NAME, account.name);
346             intent.putExtra(RawContacts.ACCOUNT_TYPE, account.type);
347             intent.putExtra(RawContacts.DATA_SET, account.dataSet);
348             intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
349                     | Intent.FLAG_ACTIVITY_FORWARD_RESULT);
350             startActivity(intent);
351             finish();
352         }
353 
354         @Override
355         public void onCustomEditContactActivityRequested(AccountWithDataSet account,
356                 Uri rawContactUri, Bundle intentExtras, boolean redirect) {
357             final AccountTypeManager accountTypes =
358                     AccountTypeManager.getInstance(ContactEditorBaseActivity.this);
359             final AccountType accountType = accountTypes.getAccountType(
360                     account.type, account.dataSet);
361 
362             Intent intent = new Intent();
363             intent.setClassName(accountType.syncAdapterPackageName,
364                     accountType.getEditContactActivityClassName());
365             intent.setAction(Intent.ACTION_EDIT);
366             intent.setData(rawContactUri);
367             if (intentExtras != null) {
368                 intent.putExtras(intentExtras);
369             }
370 
371             if (redirect) {
372                 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
373                         | Intent.FLAG_ACTIVITY_FORWARD_RESULT);
374                 startActivity(intent);
375                 finish();
376             } else {
377                 startActivity(intent);
378             }
379         }
380     };
381 
382     @Override
getDialogManager()383     public DialogManager getDialogManager() {
384         return mDialogManager;
385     }
386 }
387