Statistics
| Branch: | Revision:

root / src / com / rackspacecloud / android / ListAccountsActivity.java @ 6b8dad86

History | View | Annotate | Download (16.4 kB)

1
package com.rackspacecloud.android;
2

    
3
import java.io.FileInputStream;
4
import java.io.FileNotFoundException;
5
import java.io.FileOutputStream;
6
import java.io.IOException;
7
import java.io.ObjectInputStream;
8
import java.io.ObjectOutputStream;
9
import java.io.StreamCorruptedException;
10
import java.util.ArrayList;
11
import java.util.TreeMap;
12

    
13
import com.rackspace.cloud.loadbalancer.api.client.Algorithm;
14
import com.rackspace.cloud.loadbalancer.api.client.AlgorithmManager;
15
import com.rackspace.cloud.loadbalancer.api.client.Protocol;
16
import com.rackspace.cloud.loadbalancer.api.client.ProtocolManager;
17
import com.rackspace.cloud.servers.api.client.Account;
18
import com.rackspace.cloud.servers.api.client.Flavor;
19
import com.rackspace.cloud.servers.api.client.FlavorManager;
20
import com.rackspace.cloud.servers.api.client.Image;
21
import com.rackspace.cloud.servers.api.client.ImageManager;
22
import com.rackspace.cloud.servers.api.client.http.Authentication;
23

    
24
import android.app.AlertDialog;
25
import android.app.Dialog;
26
import android.app.ProgressDialog;
27
import android.content.Context;
28
import android.content.DialogInterface;
29
import android.content.DialogInterface.OnCancelListener;
30
import android.content.Intent;
31
import android.os.AsyncTask;
32
import android.os.Bundle;
33
import android.util.Log;
34
import android.view.ContextMenu;
35
import android.view.ContextMenu.ContextMenuInfo;
36
import android.view.LayoutInflater;
37
import android.view.Menu;
38
import android.view.MenuInflater;
39
import android.view.MenuItem;
40
import android.view.View;
41
import android.view.View.OnClickListener;
42
import android.view.ViewGroup;
43
import android.widget.AdapterView.AdapterContextMenuInfo;
44
import android.widget.ArrayAdapter;
45
import android.widget.Button;
46
import android.widget.EditText;
47
import android.widget.ImageView;
48
import android.widget.ListView;
49
import android.widget.TextView;
50
import android.widget.Toast;
51

    
52
//
53
public class ListAccountsActivity extends GaListActivity{
54

    
55
        private final int PASSWORD_PROMPT = 123;
56
        private final String FILENAME = "accounts.data";
57
        private static final String PAGE_ROOT = "/Root";
58

    
59
        private boolean authenticating;
60
        private ArrayList<Account> accounts;
61
        private Intent tabViewIntent;
62
        private ProgressDialog dialog;
63
        private Context context;
64
        private AndroidCloudApplication app;
65

    
66
        //need to store if the user has successfully logged in
67
        private boolean loggedIn;
68

    
69
        public void onCreate(Bundle savedInstanceState) {
70
                super.onCreate(savedInstanceState);
71
                trackPageView(PAGE_ROOT);
72
                onRestoreInstanceState(savedInstanceState);
73
                registerForContextMenu(getListView());
74
                context = getApplicationContext();
75
                tabViewIntent = new Intent(this, TabViewActivity.class);
76
                verifyPassword();
77
        }
78

    
79
        @Override
80
        protected void onSaveInstanceState(Bundle outState) {
81
                super.onSaveInstanceState(outState);
82
                outState.putBoolean("authenticating", authenticating);
83
                outState.putBoolean("loggedIn", loggedIn);
84
                outState.putSerializable("accounts", accounts);
85

    
86
                //need to set authenticating back to true because it is set to false
87
                //in hideDialog()
88
                if(authenticating){
89
                        hideDialog();
90
                        authenticating = true;
91
                }
92
                writeAccounts();
93
        }
94

    
95
        @SuppressWarnings("unchecked")
96
        @Override
97
        protected void onRestoreInstanceState(Bundle state) {
98

    
99
                /*
100
                 * need reference to the app so you can access
101
                 * isLoggingIn
102
                 */
103
                app = (AndroidCloudApplication)this.getApplication();
104
                
105
                if (state != null && state.containsKey("loggedIn")){
106
                        loggedIn = state.getBoolean("loggedIn");
107
                }
108
                else{
109
                        loggedIn = false;
110
                }
111

    
112
                if (state != null && state.containsKey("authenticating") && state.getBoolean("authenticating")) {
113
                        showDialog();
114
                } else {
115
                        hideDialog();
116
                }
117
                if (state != null && state.containsKey("accounts")) {
118
                        accounts = (ArrayList<Account>)state.getSerializable("accounts");
119
                        if (accounts.size() == 0) {
120
                                displayNoAccountsCell();
121
                        } else {
122
                                getListView().setDividerHeight(1); // restore divider lines 
123
                                setListAdapter(new AccountAdapter());
124
                        }
125
                } else {
126
                        loadAccounts();        
127
                }         
128
        }
129

    
130
        @Override
131
        protected void onStart(){
132
                super.onStart();
133
                if(authenticating){
134
                        showDialog();
135
                }
136
        }
137

    
138
        @Override
139
        protected void onStop(){
140
                super.onStop();
141
                if(authenticating){
142
                        hideDialog();
143
                        authenticating = true;
144
                }
145
        }
146

    
147
        /*
148
         * if the application is password protected,
149
         * the user must provide the password before
150
         * gaining access
151
         */
152
        private void verifyPassword(){
153
                PasswordManager pwManager = new PasswordManager(getSharedPreferences(
154
                                Preferences.SHARED_PREFERENCES_NAME, MODE_PRIVATE));
155
                if(pwManager.hasPassword() && !loggedIn){
156
                        createCustomDialog(PASSWORD_PROMPT);
157
                }
158
        }
159

    
160
        private boolean rightPassword(String password){
161
                PasswordManager pwManager = new PasswordManager(getSharedPreferences(
162
                                Preferences.SHARED_PREFERENCES_NAME, MODE_PRIVATE));
163
                return pwManager.verifyEnteredPassword(password);
164
        }
165

    
166

    
167
        /*
168
         * forces the user to enter a correct password
169
         * before they gain access to application data
170
         */
171
        private void createCustomDialog(int id) {
172
                final Dialog dialog = new Dialog(ListAccountsActivity.this);
173
                switch (id) {
174
                case PASSWORD_PROMPT:
175
                        dialog.setContentView(R.layout.passworddialog);
176
                        dialog.setTitle("Enter your password:");
177
                        dialog.setCancelable(false);
178
                        Button button = (Button) dialog.findViewById(R.id.submit_password);
179
                        button.setOnClickListener(new OnClickListener() {
180
                                public void onClick(View v){
181
                                        EditText passwordText = ((EditText)dialog.findViewById(R.id.submit_password_text));
182
                                        if(!rightPassword(passwordText.getText().toString())){
183
                                                passwordText.setText("");
184
                                                showToast("Password was incorrect.");
185
                                                loggedIn = false;
186
                                        }
187
                                        else{
188
                                                dialog.dismiss();
189
                                                loggedIn = true;
190
                                        }
191
                                }
192

    
193
                        });
194
                        dialog.show();
195
                }
196
        }
197

    
198
        private void loadAccounts() {
199
                //check and see if there are any in memory
200
                if(accounts == null){
201
                        accounts = readAccounts();
202
                }
203
                //if nothing was written before accounts will still be null
204
                if(accounts == null){
205
                        accounts = new ArrayList<Account>();
206
                }
207

    
208
                setAccountList();
209
        }
210

    
211
        private void setAccountList() {
212

    
213
                if (accounts.size() == 0) {
214
                        displayNoAccountsCell();
215
                } else {
216
                        getListView().setDividerHeight(1); // restore divider lines 
217
                        this.setListAdapter(new AccountAdapter());
218
                }
219
        }
220

    
221
        private void writeAccounts(){
222
                FileOutputStream fos;
223
                ObjectOutputStream out = null;
224
                try{
225
                        fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
226
                        out = new ObjectOutputStream(fos);
227
                        out.writeObject(accounts);
228
                        out.flush();
229
                        out.close();
230
                } catch (FileNotFoundException e) {
231
                        showAlert("Error", "Could not save accounts.");
232
                        e.printStackTrace();
233
                } catch (IOException e) {
234
                        showAlert("Error", "Could not save accounts.");
235
                        e.printStackTrace();
236
                }
237
        }
238

    
239
        private ArrayList<Account> readAccounts(){
240
                FileInputStream fis;
241
                ObjectInputStream in;
242
                try {
243
                        fis = openFileInput(FILENAME);
244
                        in = new ObjectInputStream(fis);
245
                        @SuppressWarnings("unchecked")
246
                        ArrayList<Account> file = (ArrayList<Account>)in.readObject();
247
                        in.close();
248
                        return file; 
249
                } catch (FileNotFoundException e) {
250
                        //showAlert("Error", "Could not load accounts.");
251
                        e.printStackTrace();
252
                        return null;
253
                } catch (StreamCorruptedException e) {
254
                        showAlert("Error", "Could not load accounts.");
255
                        e.printStackTrace();
256
                } catch (IOException e) {
257
                        showAlert("Error", "Could not load accounts.");
258
                        e.printStackTrace();
259
                } catch (ClassNotFoundException e) {
260
                        showAlert("Error", "Could not load accounts.");
261
                        e.printStackTrace();
262
                }
263
                return null;
264

    
265
        }
266

    
267
        private void displayNoAccountsCell() {
268
                String a[] = new String[1];
269
                a[0] = "No Accounts";
270
                setListAdapter(new ArrayAdapter<String>(getApplicationContext(), R.layout.noaccountscell, R.id.no_accounts_label, a));
271
                getListView().setTextFilterEnabled(true);
272
                getListView().setDividerHeight(0); // hide the dividers so it won't look like a list row
273
                getListView().setItemsCanFocus(false);
274
        }
275

    
276
        protected void onListItemClick(ListView l, View v, int position, long id) {
277
                if (accounts != null && accounts.size() > 0) {
278
                        //setActivityIndicatorsVisibility(View.VISIBLE, v);
279
                        Account.setAccount(accounts.get(position));
280
                        login();
281
                }                
282
        }
283

    
284
        public void login() {
285
                //showActivityIndicators();
286
                //setLoginPreferences();
287
                new AuthenticateTask().execute((Void[]) null);
288
        }
289

    
290
        //setup menu for when menu button is pressed
291
        public boolean onCreateOptionsMenu(Menu menu) {
292
                super.onCreateOptionsMenu(menu);
293
                MenuInflater inflater = getMenuInflater();
294
                inflater.inflate(R.menu.accounts_list_menu, menu);
295
                return true;
296
        } 
297

    
298
        @Override 
299
        //in options menu, when add account is selected go to add account activity
300
        public boolean onOptionsItemSelected(MenuItem item) {
301
                switch (item.getItemId()) {
302
                case R.id.add_account:
303
                        startActivityForResult(new Intent(this, AddAccountActivity.class), 78); // arbitrary number; never used again
304
                        return true;
305

    
306
                case R.id.contact_rackspace:
307
                        startActivity(new Intent(this, ContactActivity.class));
308
                        return true;
309

    
310
                case R.id.add_password:
311
                        startActivity(new Intent(this, CreatePasswordActivity.class));
312
                        return true;
313
                }        
314
                return false;
315
        } 
316

    
317
        //the context menu for a long press on an account
318
        public void onCreateContextMenu(ContextMenu menu, View v,
319
                        ContextMenuInfo menuInfo) {
320
                super.onCreateContextMenu(menu, v, menuInfo);
321
                MenuInflater inflater = getMenuInflater();
322
                inflater.inflate(R.menu.account_context_menu, menu);
323
        }
324

    
325
        //removes the selected account from account list if remove is clicked
326
        public boolean onContextItemSelected(MenuItem item) {
327
                AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
328
                accounts.remove(info.position);
329
                writeAccounts();
330
                loadAccounts();
331
                return true;
332
        }
333

    
334
        class AccountAdapter extends ArrayAdapter<Account> {
335

    
336
                AccountAdapter() {
337
                        super(ListAccountsActivity.this, R.layout.listaccountcell, accounts);
338
                }
339

    
340
                public View getView(int position, View convertView, ViewGroup parent) {
341

    
342
                        LayoutInflater inflater = getLayoutInflater();
343
                        View row = inflater.inflate(R.layout.listaccountcell, parent, false);
344

    
345
                        TextView label = (TextView) row.findViewById(R.id.label);
346
                        label.setText(accounts.get(position).getUsername());
347

    
348
                        TextView sublabel = (TextView) row.findViewById(R.id.sublabel);
349
                        sublabel.setText(getAccountServer(accounts.get(position)));
350

    
351
                        ImageView icon = (ImageView) row.findViewById(R.id.account_type_icon);
352
                        icon.setImageResource(setAccountIcon(accounts.get(position)));
353

    
354
                        return row;
355
                }
356
        }
357

    
358
        public String getAccountServer(Account account){
359
                String authServer = account.getAuthServer();
360
                String result;
361
                if(authServer.equals(Preferences.COUNTRY_UK_AUTH_SERVER)){
362
                        result = "Rackspace Cloud (UK)";
363
                }
364
                else if(authServer.equals(Preferences.COUNTRY_US_AUTH_SERVER)){
365
                        result = "Rackspace Cloud (US)";
366
                }
367
                else{
368
                        result = "Custom";
369
                        //setCustomIcon();
370
                }
371
                return result;
372
        }
373

    
374
        //display rackspace logo for cloud accounts and openstack logo for others
375
        private int setAccountIcon(Account account){
376
                if(account.getAuthServer().equals(Preferences.COUNTRY_UK_AUTH_SERVER) 
377
                                || account.getAuthServer().equals(Preferences.COUNTRY_US_AUTH_SERVER)){
378
                        return R.drawable.rackspacecloud_icon;
379
                }
380
                else{
381
                        return R.drawable.openstack_icon;
382
                }
383
        }
384

    
385
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
386
                super.onActivityResult(requestCode, resultCode, data);
387

    
388
                if(requestCode == 187){
389
                        hideDialog(); 
390
                }
391

    
392
                if (resultCode == RESULT_OK && requestCode == 78) {          
393
                        Account acc = new Account();
394
                        Bundle b = data.getBundleExtra("accountInfo");
395
                        acc.setApiKey(b.getString("apiKey"));
396
                        acc.setUsername(b.getString("username"));
397
                        acc.setAuthServer(b.getString("server"));
398
                        accounts.add(acc);
399
                        writeAccounts();
400
                        loadAccounts();
401
                }
402
        }        
403

    
404
        private void showDialog() {
405
                app.setIsLoggingIn(true);
406
                authenticating = true;
407
                if(dialog == null || !dialog.isShowing()){
408
                        dialog = ProgressDialog.show(ListAccountsActivity.this, "", "Authenticating...", true);
409
                        dialog.setCancelable(true);
410
                        dialog.setOnCancelListener(new OnCancelListener() {
411

    
412
                                @Override
413
                                public void onCancel(DialogInterface dialog) {
414
                                        app.setIsLoggingIn(false);
415
                                        hideDialog();
416
                                }
417
                        });
418
                }
419
        }
420

    
421
        private void hideDialog() {
422
                if(dialog != null){
423
                        dialog.dismiss();
424
                }
425
                authenticating = false;
426
        }
427

    
428
        private class AuthenticateTask extends AsyncTask<Void, Void, Boolean> {
429

    
430
                @Override
431
                protected void onPreExecute(){
432
                        showDialog();
433
                }
434

    
435
                @Override
436
                protected Boolean doInBackground(Void... arg0) {
437
                        if(isCancelled()){
438
                                return false;
439
                        }
440
                        return new Boolean(Authentication.authenticate(context));
441
                }
442

    
443
                @Override
444
                protected void onPostExecute(Boolean result) {
445
                        if (result.booleanValue()) {
446
                                //startActivity(tabViewIntent);
447
                                if(app.isLogginIn()){
448
                                        new LoadImagesTask().execute((Void[]) null);
449
                                } else {
450
                                        hideDialog();
451
                                }
452
                        } else {
453
                                hideDialog();
454
                                showAlert("Login Failure", "Authentication failed.  Please check your User Name and API Key.");
455
                        }
456
                }
457
        }
458

    
459
        private class LoadImagesTask extends AsyncTask<Void, Void, ArrayList<Image>> {
460
 
461
                @Override
462
                protected ArrayList<Image> doInBackground(Void... arg0) {
463
                        Log.d("info", "LoadImagesTask Started");
464
                        return (new ImageManager()).createList(true, context);
465
                }
466

    
467
                @Override
468
                protected void onPostExecute(ArrayList<Image> result) {
469
                        if (result != null && result.size() > 0) {
470
                                TreeMap<String, Image> imageMap = new TreeMap<String, Image>();
471
                                for (int i = 0; i < result.size(); i++) {
472
                                        Image image = result.get(i);
473
                                        imageMap.put(image.getId(), image);
474
                                }
475
                                Image.setImages(imageMap);
476
                                if(app.isLogginIn()){
477
                                        new LoadProtocolsTask().execute((Void[]) null); 
478
                                } else {
479
                                        hideDialog();
480
                                }
481
                        } else {
482
                                hideDialog();
483
                                showAlert("Login Failure", "There was a problem loading server images.  Please try again.");
484
                        }
485
                }
486
        }
487

    
488
        private class LoadProtocolsTask extends AsyncTask<Void, Void, ArrayList<Protocol>> {
489

    
490
                @Override
491
                protected ArrayList<Protocol> doInBackground(Void... arg0) {
492
                        Log.d("info", "LoadProtocolsTask Started");
493
                        return (new ProtocolManager()).createList(context);
494
                }
495

    
496
                @Override
497
                protected void onPostExecute(ArrayList<Protocol> result) {
498
                        if (result != null && result.size() > 0) {
499
                                Protocol.setProtocols(result);
500
                                if(app.isLogginIn()){
501
                                        new LoadAlgorithmsTask().execute((Void[]) null);
502
                                } else {
503
                                        hideDialog();
504
                                }
505
                        } else {
506
                                hideDialog();
507
                                showAlert("Login Failure", "There was a problem loading load balancer protocols.  Please try again.");
508
                        }
509
                }
510
        }
511

    
512
        private class LoadAlgorithmsTask extends AsyncTask<Void, Void, ArrayList<Algorithm>> {
513

    
514
                @Override
515
                protected ArrayList<Algorithm> doInBackground(Void... arg0) {
516
                        Log.d("info", "LoadAlgorithmsTask Started");
517
                        return (new AlgorithmManager()).createList(context);
518
                }
519

    
520
                @Override
521
                protected void onPostExecute(ArrayList<Algorithm> result) {
522
                        if (result != null && result.size() > 0) {
523
                                Algorithm.setAlgorithms(result);
524
                                if(app.isLogginIn()){
525
                                        new LoadFlavorsTask().execute((Void[]) null);
526
                                } else {
527
                                        hideDialog();
528
                                }
529
                        } else {
530
                                hideDialog();
531
                                showAlert("Login Failure", "There was a problem loading load balancer algorithms.  Please try again.");
532
                        }
533
                }
534
        }
535

    
536
        private class LoadFlavorsTask extends AsyncTask<Void, Void, ArrayList<Flavor>> {
537

    
538
                @Override
539
                protected ArrayList<Flavor> doInBackground(Void... arg0) {
540
                        Log.d("info", "LoadFlavorsTask Started");
541
                        return (new FlavorManager()).createList(true, context);
542
                }
543

    
544
                @Override
545
                protected void onPostExecute(ArrayList<Flavor> result) {
546
                        if(isCancelled()){
547
                                return;
548
                        }
549
                        
550
                        if (result != null && result.size() > 0) {
551
                                TreeMap<String, Flavor> flavorMap = new TreeMap<String, Flavor>();
552
                                for (int i = 0; i < result.size(); i++) {
553
                                        Flavor flavor = result.get(i);
554
                                        flavorMap.put(flavor.getId(), flavor);
555
                                }
556
                                Flavor.setFlavors(flavorMap);
557
                                if(isCancelled()){
558
                                        return;
559
                                }
560
                                hideDialog();
561
                                Log.d("info", "Starting TabViewIntent");
562
                                if(app.isLogginIn()){
563
                                        startActivityForResult(tabViewIntent, 187);
564
                                } else {
565
                                        hideDialog();
566
                                }
567
                        } else {
568
                                hideDialog();
569
                                showAlert("Login Failure", "There was a problem loading server flavors.  Please try again.");
570
                        }
571
                }
572
        }
573

    
574

    
575
        private void showAlert(String title, String message) {
576
                AlertDialog alert = new AlertDialog.Builder(this).create();
577
                alert.setTitle(title);
578
                alert.setMessage(message);
579
                alert.setButton("OK", new DialogInterface.OnClickListener() {
580
                        public void onClick(DialogInterface dialog, int which) {
581
                                return;
582
                        } }); 
583
                alert.show();
584
        }
585

    
586
        private void showToast(String message) {
587
                Context context = getApplicationContext();
588
                int duration = Toast.LENGTH_SHORT;
589
                Toast toast = Toast.makeText(context, message, duration);
590
                toast.show();
591
        }
592

    
593

    
594

    
595

    
596
}