/android/import-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/import-contacts
6 by edam
- added GPL header comments to all files
1
/*
2
 * Doit.java
3
 *
4
 * Copyright (C) 2009 Tim Marston <edam@waxworlds.org>
5
 *
6
 * This file is part of the Import Contacts program (hereafter referred
7
 * to as "this program"). For more information, see
8
 * http://www.waxworlds.org/edam/software/android/import-contacts
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
24
package org.waxworlds.edam.importcontacts;
1 by edam
Initial import
25
26
import android.app.AlertDialog;
27
import android.app.Dialog;
28
import android.content.DialogInterface;
29
import android.content.Intent;
30
import android.os.Bundle;
31
import android.os.Handler;
32
import android.os.Message;
33
import android.view.LayoutInflater;
34
import android.view.View;
35
import android.view.View.OnClickListener;
36
import android.widget.Button;
37
import android.widget.CheckBox;
38
import android.widget.CompoundButton;
39
import android.widget.ProgressBar;
40
import android.widget.TextView;
2 by edam
- added toaster message about import abortion in onPause()
41
import android.widget.Toast;
1 by edam
Initial import
42
43
public class Doit extends WizardActivity
44
{
45
	private final static int DIALOG_ERROR = 0;
46
	private final static int DIALOG_CONTINUEORABORT = 1;
47
	private final static int DIALOG_MERGEPROMPT = 2;
48
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
49
	public final static int MESSAGE_ALLDONE = 0;
50
	public final static int MESSAGE_ABORT = 1;
3 by edam
- added "all done" message
51
	public final static int MESSAGE_ERROR = 3;
52
	public final static int MESSAGE_CONTINUEORABORT = 4;
53
	public final static int MESSAGE_SETPROGRESSMESSAGE = 5;
54
	public final static int MESSAGE_SETMAXPROGRESS = 6;
55
	public final static int MESSAGE_SETTMPPROGRESS = 7;
56
	public final static int MESSAGE_SETPROGRESS = 8;
57
	public final static int MESSAGE_MERGEPROMPT = 9;
58
	public final static int MESSAGE_CONTACTOVERWRITTEN = 10;
59
	public final static int MESSAGE_CONTACTCREATED = 11;
60
	public final static int MESSAGE_CONTACTMERGED = 12;
61
	public final static int MESSAGE_CONTACTSKIPPED = 13;
62
9 by edam
- added scroll view to all layouts
63
	public final static int ACTION_PROMPT = 0;
64
	public final static int ACTION_KEEP = 1;
65
	public final static int ACTION_MERGE_MERGE = 2;
66
	public final static int ACTION_OVERWRITE = 3;
67
10 by edam
- made behaviour of next button overridable
68
	public final static int NEXT_BEGIN = 0;
69
	public final static int NEXT_CLOSE = 1;
70
1 by edam
Initial import
71
	private boolean _startedProgress;
72
	private int _maxProgress;
73
	private int _tmpProgress;
74
	private int _progress;
75
	protected String _dialogMessage;
76
	private Dialog _mergePromptDialog;
77
	private boolean _mergePromptAlwaysSelected;
10 by edam
- made behaviour of next button overridable
78
	private int _nextAction;
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
79
	private int _currentDialogId;
1 by edam
Initial import
80
81
	private int _countOverwrites;
82
	private int _countCreates;
83
	private int _countMerges;
84
	private int _countSkips;
85
3 by edam
- added "all done" message
86
	protected Importer _importer = null;
1 by edam
Initial import
87
88
	public Handler _handler;
89
90
	public class DoitHandler extends Handler
91
	{
92
		@Override
93
		public void handleMessage( Message msg ) {
94
			switch( msg.what )
95
			{
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
96
			case MESSAGE_ALLDONE:
3 by edam
- added "all done" message
97
				( (TextView)findViewById( R.id.doit_alldone ) ).
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
98
					setVisibility( View.VISIBLE );
99
				( (Button)findViewById( R.id.back ) ).setEnabled( false );
10 by edam
- made behaviour of next button overridable
100
				updateNext( NEXT_CLOSE );
101
				findViewById( R.id.doit_abort_disp ).setVisibility(
102
						View.GONE );
1 by edam
Initial import
103
				break;
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
104
			case MESSAGE_ABORT:
105
				manualAbort();
1 by edam
Initial import
106
				break;
3 by edam
- added "all done" message
107
			case MESSAGE_ERROR:
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
108
				_dialogMessage = (String)msg.obj;
1 by edam
Initial import
109
				showDialog( DIALOG_ERROR );
110
				break;
3 by edam
- added "all done" message
111
			case MESSAGE_CONTINUEORABORT:
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
112
				_dialogMessage = (String)msg.obj;
1 by edam
Initial import
113
				showDialog( DIALOG_CONTINUEORABORT );
114
				break;
3 by edam
- added "all done" message
115
			case MESSAGE_SETPROGRESSMESSAGE:
1 by edam
Initial import
116
				( (TextView)findViewById( R.id.doit_percentage ) ).
117
						setText( (String)msg.obj );
118
				break;
3 by edam
- added "all done" message
119
			case MESSAGE_SETMAXPROGRESS:
1 by edam
Initial import
120
				if( _maxProgress > 0 ) {
10 by edam
- made behaviour of next button overridable
121
					if( _tmpProgress == _maxProgress - 1 )
1 by edam
Initial import
122
						_tmpProgress = (Integer)msg.obj;
10 by edam
- made behaviour of next button overridable
123
					if( _progress == _maxProgress - 1 )
1 by edam
Initial import
124
						_progress = (Integer)msg.obj;
125
				}
126
				_maxProgress = (Integer)msg.obj;
127
				updateProgress();
128
				break;
3 by edam
- added "all done" message
129
			case MESSAGE_SETTMPPROGRESS:
1 by edam
Initial import
130
				_tmpProgress = (Integer)msg.obj;
131
				updateProgress();
132
				break;
3 by edam
- added "all done" message
133
			case MESSAGE_SETPROGRESS:
1 by edam
Initial import
134
				_startedProgress = true;
135
				_progress = (Integer)msg.obj;
136
				updateProgress();
137
				break;
3 by edam
- added "all done" message
138
			case MESSAGE_MERGEPROMPT:
1 by edam
Initial import
139
				_dialogMessage = (String)msg.obj;
140
				showDialog( DIALOG_MERGEPROMPT );
141
				break;
3 by edam
- added "all done" message
142
			case MESSAGE_CONTACTOVERWRITTEN:
1 by edam
Initial import
143
				_countOverwrites++;
144
				updateStats();
145
				break;
3 by edam
- added "all done" message
146
			case MESSAGE_CONTACTCREATED:
1 by edam
Initial import
147
				_countCreates++;
148
				updateStats();
149
				break;
3 by edam
- added "all done" message
150
			case MESSAGE_CONTACTMERGED:
1 by edam
Initial import
151
				_countMerges++;
152
				updateStats();
153
				break;
3 by edam
- added "all done" message
154
			case MESSAGE_CONTACTSKIPPED:
1 by edam
Initial import
155
				_countSkips++;
156
				updateStats();
157
				break;
158
			default:
159
				super.handleMessage( msg );
160
			}
161
		}
162
	}
163
164
	@Override
165
	protected void onCreate(Bundle savedInstanceState)
166
	{
167
		setContentView( R.layout.doit );
168
		super.onCreate( savedInstanceState );
169
170
		// hide page 2
171
		( findViewById( R.id.doit_page_2 ) ).setVisibility( View.GONE );
172
10 by edam
- made behaviour of next button overridable
173
		// set up abort button
174
		Button begin = (Button)findViewById( R.id.abort );
1 by edam
Initial import
175
		begin.setOnClickListener( new View.OnClickListener() {
176
			public void onClick( View view ) {
10 by edam
- made behaviour of next button overridable
177
				manualAbort();
1 by edam
Initial import
178
			}
179
		} );
180
181
		_startedProgress = false;
182
		_maxProgress = 0;
183
		_tmpProgress = 0;
184
		_progress = 0;
185
		_handler = new DoitHandler();
186
187
		_countOverwrites = 0;
188
		_countCreates = 0;
189
		_countMerges = 0;
190
		_countSkips = 0;
191
10 by edam
- made behaviour of next button overridable
192
		updateNext( NEXT_BEGIN );
193
1 by edam
Initial import
194
		updateProgress();
195
		updateStats();
196
	}
197
198
	@Override
199
	protected void onPause()
200
	{
201
		super.onPause();
202
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
203
		// close any open dialogs
204
		try {
205
			dismissDialog( _currentDialogId );
206
		}
207
		catch( Exception e ) {
208
		}
209
2 by edam
- added toaster message about import abortion in onPause()
210
		// saving the state of an import sounds complicated! Lets just abort!
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
211
		manualAbort( true );
1 by edam
Initial import
212
	}
213
214
	@Override
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
215
	protected Dialog onCreateDialog( int id )
1 by edam
Initial import
216
	{
217
		switch( id )
218
		{
219
		case DIALOG_ERROR:
220
			return new AlertDialog.Builder( this )
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
221
				.setIcon( R.drawable.alert_dialog_icon )
222
				.setTitle( R.string.error_title )
223
				.setMessage( "" )
224
				.setPositiveButton( R.string.error_ok,
225
					new DialogInterface.OnClickListener() {
1 by edam
Initial import
226
						public void onClick(DialogInterface dialog,
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
227
							int whichButton)
228
						{
1 by edam
Initial import
229
							Doit.this._importer.wake();
230
						}
231
					} )
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
232
				.setOnCancelListener( _dialogOnCancelListener )
233
				.create();
1 by edam
Initial import
234
		case DIALOG_CONTINUEORABORT:
235
			return new AlertDialog.Builder( this )
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
236
				.setIcon( R.drawable.alert_dialog_icon )
237
				.setTitle( R.string.error_title )
238
				.setMessage( "" )
239
				.setPositiveButton( R.string.error_continue,
240
					new DialogInterface.OnClickListener() {
241
						public void onClick(DialogInterface dialog,
242
							int whichButton)
243
						{
244
							Doit.this._importer.wake(
245
								Importer.RESPONSE_POSITIVE );
246
						}
247
					} )
248
				.setNegativeButton( R.string.error_abort,
249
					new DialogInterface.OnClickListener() {
250
						public void onClick(DialogInterface dialog,
251
							int whichButton)
252
						{
253
							Doit.this._importer.wake(
254
								Importer.RESPONSE_NEGATIVE );
255
						}
256
					} )
257
				.setOnCancelListener( _dialogOnCancelListener )
258
				.create();
1 by edam
Initial import
259
		case DIALOG_MERGEPROMPT:
260
			// custom layout in an AlertDialog
261
			LayoutInflater factory = LayoutInflater.from( this );
262
			final View dialogView = factory.inflate(
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
263
				R.layout.mergeprompt, null );
1 by edam
Initial import
264
			( (CheckBox)dialogView.findViewById( R.id.mergeprompt_always ) ).
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
265
				setOnCheckedChangeListener(
266
					new CompoundButton.OnCheckedChangeListener() {
267
						public void onCheckedChanged( CompoundButton buttonView,
268
							boolean isChecked )
269
						{
270
							Doit.this._mergePromptAlwaysSelected = isChecked;
271
						}
272
					} );
1 by edam
Initial import
273
			( (Button)dialogView.findViewById( R.id.merge_keep ) ).
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
274
				setOnClickListener( _mergePromptButtonListener );
1 by edam
Initial import
275
			( (Button)dialogView.findViewById( R.id.merge_overwrite ) ).
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
276
				setOnClickListener( _mergePromptButtonListener );
1 by edam
Initial import
277
			( (Button)dialogView.findViewById( R.id.merge_merge ) ).
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
278
				setOnClickListener( _mergePromptButtonListener );
10 by edam
- made behaviour of next button overridable
279
			( (Button)dialogView.findViewById( R.id.abort ) ).
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
280
				setOnClickListener( _mergePromptButtonListener );
1 by edam
Initial import
281
			_mergePromptAlwaysSelected = false;
282
			return new AlertDialog.Builder( this )
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
283
				.setIcon( R.drawable.alert_dialog_icon )
284
				.setTitle( R.string.mergeprompt_title )
285
				.setView( dialogView )
286
				.setOnCancelListener( _dialogOnCancelListener )
287
				.create();
1 by edam
Initial import
288
		}
289
		return null;
290
	}
291
13 by edam
- converted project to use Android 1.5 SDK
292
	private OnClickListener _mergePromptButtonListener = new OnClickListener() {
10 by edam
- made behaviour of next button overridable
293
		public void onClick( View view )
294
		{
295
			// handle abort
296
			if( view.getId() == R.id.abort )
297
				manualAbort();
298
299
			// else, response
300
			else {
301
				int responseExtra = _mergePromptAlwaysSelected?
302
						Importer.RESPONSEEXTRA_ALWAYS : Importer.RESPONSEEXTRA_NONE;
303
				Doit.this._importer.wake( convertIdToAction( view.getId() ),
304
						responseExtra );
305
			}
306
307
			// close dialog and free (don't keep a reference)
1 by edam
Initial import
308
			Doit.this._mergePromptDialog.dismiss();
10 by edam
- made behaviour of next button overridable
309
			Doit.this._mergePromptDialog = null;
1 by edam
Initial import
310
		}
311
	};
312
10 by edam
- made behaviour of next button overridable
313
	@Override
314
	protected void onNext()
315
	{
316
		Button next = (Button)findViewById( R.id.next );
317
		next.setEnabled( false );
318
319
		switch( _nextAction )
320
		{
321
		case NEXT_BEGIN:
322
			importContacts();
323
			break;
324
		case NEXT_CLOSE:
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
325
			setResult( RESULT_OK );
10 by edam
- made behaviour of next button overridable
326
			finish();
327
			break;
328
		}
329
	}
330
331
	private void manualAbort()
332
	{
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
333
		manualAbort( false );
334
	}
335
336
	private void manualAbort( boolean showToasterPopup )
337
	{
338
		abortImport( showToasterPopup );
339
10 by edam
- made behaviour of next button overridable
340
		updateNext( NEXT_CLOSE );
341
		( (Button)findViewById( R.id.back ) ).setEnabled( true );
342
		findViewById( R.id.doit_abort_disp ).setVisibility( View.GONE );
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
343
		( (TextView)findViewById( R.id.doit_aborted ) ).
344
			setVisibility( View.VISIBLE );
345
		( (TextView)findViewById( R.id.doit_alldone ) ).
346
			setVisibility( View.GONE );
10 by edam
- made behaviour of next button overridable
347
	}
348
349
	private void updateNext( int nextAction )
350
	{
351
		Button next = (Button)findViewById( R.id.next );
352
		switch( nextAction ) {
353
		case NEXT_BEGIN:	next.setText( R.string.doit_begin ); break;
354
		case NEXT_CLOSE:	next.setText( R.string.doit_close ); break;
355
		}
356
		next.setEnabled( true );
357
		_nextAction = nextAction;
358
	}
359
9 by edam
- added scroll view to all layouts
360
	public static int convertIdToAction( int id ) {
361
		switch( id ) {
362
		case R.id.merge_keep:		return ACTION_KEEP;
363
		case R.id.merge_merge:		return ACTION_MERGE_MERGE;
364
		case R.id.merge_overwrite:	return ACTION_OVERWRITE;
365
		default: return ACTION_PROMPT;
366
		}
367
	}
368
369
	public static int convertActionToId( int action ) {
370
		switch( action ) {
371
		case ACTION_KEEP:		return R.id.merge_keep;
372
		case ACTION_MERGE_MERGE:return R.id.merge_merge;
373
		case ACTION_OVERWRITE:	return R.id.merge_overwrite;
374
		default: return R.id.merge_prompt;
375
		}
376
	}
377
1 by edam
Initial import
378
	private DialogInterface.OnCancelListener _dialogOnCancelListener =
379
			new DialogInterface.OnCancelListener() {
380
		public void onCancel( DialogInterface dialog ) {
381
			setResult( RESULT_CANCELED );
382
			finish();
383
		}
384
	};
385
386
	@Override
387
	protected void onActivityResult( int requestCode, int resultCode,
388
			Intent data )
389
	{
2 by edam
- added toaster message about import abortion in onPause()
390
		// if we're cancelling, abort any import
1 by edam
Initial import
391
		if( resultCode == RESULT_CANCELED )
10 by edam
- made behaviour of next button overridable
392
			abortImport( true );
1 by edam
Initial import
393
	}
394
395
	@Override
396
	protected void onPrepareDialog(int id, Dialog dialog)
397
	{
14 by edam
- got rid of the pretend ImportContacts activity alltogether (and made the Intro activity the startup one)
398
		_currentDialogId = id;
399
1 by edam
Initial import
400
		switch( id )
401
		{
402
		case DIALOG_ERROR:	// fall through
403
		case DIALOG_CONTINUEORABORT:
404
			// set dialog message
405
			( (AlertDialog)dialog ).setMessage( _dialogMessage );
406
			break;
407
		case DIALOG_MERGEPROMPT:
408
			// set contact's name
409
			( (TextView)dialog.findViewById( R.id.mergeprompt_name ) ).setText(
410
					_dialogMessage );
411
			// and set up reference to dialog
412
			_mergePromptDialog = dialog;
413
			break;
414
		}
415
416
		super.onPrepareDialog( id, dialog );
417
	}
418
419
	private void importContacts()
420
	{
421
		// switch interfaces
422
		( findViewById( R.id.doit_page_1 ) ).setVisibility( View.GONE );
423
		( findViewById( R.id.doit_page_2 ) ).setVisibility( View.VISIBLE );
424
425
		// disable back button
426
		( (Button)findViewById( R.id.back ) ).setEnabled( false );
427
428
		// create importer
429
		_importer = new VCFImporter( this );
430
431
		// start the service's thread
432
		_importer.start();
433
	}
434
435
	private void updateProgress()
436
	{
437
		ProgressBar bar = (ProgressBar)findViewById( R.id.doit_progress );
438
		TextView outOf = (TextView)findViewById( R.id.doit_outof );
439
440
		if( _maxProgress > 0 )
441
		{
442
			bar.setMax( _maxProgress );
443
			bar.setSecondaryProgress( _tmpProgress );
444
445
			if( _startedProgress )
446
			{
447
				( (TextView)findViewById( R.id.doit_percentage ) ).setText(
448
						(int)Math.round( 100 * _progress / _maxProgress ) + "%" );
449
				outOf.setText( _progress + "/" + _maxProgress );
450
				bar.setProgress( _progress );
451
			}
452
		}
453
	}
454
455
	private void updateStats()
456
	{
457
		( (TextView)findViewById( R.id.doit_overwrites ) ).setText(
458
				"" + _countOverwrites );
459
		( (TextView)findViewById( R.id.doit_creates ) ).setText(
460
				"" + _countCreates );
461
		( (TextView)findViewById( R.id.doit_merges ) ).setText(
462
				"" + _countMerges );
463
		( (TextView)findViewById( R.id.doit_skips ) ).setText(
464
				"" + _countSkips );
465
	}
466
10 by edam
- made behaviour of next button overridable
467
	private void abortImport( boolean showToasterPopup )
1 by edam
Initial import
468
	{
469
		if( _importer != null )
470
		{
3 by edam
- added "all done" message
471
			// try and flag worker thread - did we need to?
472
			if( _importer.setAbort() )
473
			{
474
				// wait for worker thread to end
475
				while( true ) {
476
					try {
477
						_importer.join();
478
						break;
479
					}
480
					catch( InterruptedException e ) {}
1 by edam
Initial import
481
				}
3 by edam
- added "all done" message
482
483
				// notify the user
10 by edam
- made behaviour of next button overridable
484
				if( showToasterPopup )
485
					Toast.makeText( this, R.string.doit_importaborted,
486
							Toast.LENGTH_LONG ).show();
1 by edam
Initial import
487
			}
488
		}
10 by edam
- made behaviour of next button overridable
489
490
		// destroy some stuff
491
		_importer = null;
492
		_handler = null;
1 by edam
Initial import
493
	}
494
}